Import seafile-client_7.0.2.orig.tar.xz
authorMoritz Schlarb <schlarbm@uni-mainz.de>
Tue, 8 Oct 2019 13:07:37 +0000 (14:07 +0100)
committerMoritz Schlarb <schlarbm@uni-mainz.de>
Tue, 8 Oct 2019 13:07:37 +0000 (14:07 +0100)
[dgit import orig seafile-client_7.0.2.orig.tar.xz]

699 files changed:
.clang-format [new file with mode: 0644]
.gitignore [new file with mode: 0644]
.travis.yml [new file with mode: 0644]
.tx/config [new file with mode: 0644]
Application.manifest [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
Doxyfile.in [new file with mode: 0644]
Info.plist [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README.md [new file with mode: 0644]
coding-style.md [new file with mode: 0644]
data/icons/128x128/apps/seafile.png [new file with mode: 0644]
data/icons/16x16/apps/seafile.png [new file with mode: 0644]
data/icons/22x22/apps/seafile.png [new file with mode: 0644]
data/icons/24x24/apps/seafile.png [new file with mode: 0644]
data/icons/32x32/apps/seafile.png [new file with mode: 0644]
data/icons/48x48/apps/seafile.png [new file with mode: 0644]
data/icons/scalable/apps/seafile.svg [new file with mode: 0755]
data/seafile.desktop [new file with mode: 0644]
debian/README.Debian [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/seafile-gui.install [new file with mode: 0644]
debian/source/format [new file with mode: 0644]
dev-guide.md [new file with mode: 0644]
extensions/CMakeLists.txt [new file with mode: 0644]
extensions/README.md [new file with mode: 0644]
extensions/README.org [new file with mode: 0644]
extensions/applet-connection.cpp [new file with mode: 0644]
extensions/applet-connection.h [new file with mode: 0644]
extensions/build.sh [new file with mode: 0644]
extensions/class-factory.cpp [new file with mode: 0644]
extensions/class-factory.h [new file with mode: 0644]
extensions/commands.cpp [new file with mode: 0644]
extensions/commands.h [new file with mode: 0644]
extensions/context-menu.cpp [new file with mode: 0644]
extensions/debug-register.reg [new file with mode: 0644]
extensions/debug-unregister.reg [new file with mode: 0644]
extensions/dll.cpp [new file with mode: 0644]
extensions/error.ico [new file with mode: 0644]
extensions/ext-common.h [new file with mode: 0644]
extensions/ext-utils.cpp [new file with mode: 0644]
extensions/ext-utils.h [new file with mode: 0644]
extensions/guids.h [new file with mode: 0644]
extensions/i18n.cpp [new file with mode: 0644]
extensions/i18n.h [new file with mode: 0644]
extensions/icon-overlay.cpp [new file with mode: 0644]
extensions/locked-by-me.ico [new file with mode: 0755]
extensions/locked-by-others.ico [new file with mode: 0755]
extensions/log.cpp [new file with mode: 0644]
extensions/log.h [new file with mode: 0644]
extensions/normal.ico [new file with mode: 0644]
extensions/paused.ico [new file with mode: 0644]
extensions/readonly.ico [new file with mode: 0644]
extensions/seafile_shell_ext.def [new file with mode: 0644]
extensions/seafile_shell_ext.rc [new file with mode: 0644]
extensions/shell-ext.cpp [new file with mode: 0644]
extensions/shell-ext.h [new file with mode: 0644]
extensions/syncing.ico [new file with mode: 0644]
fsplugin/.clang-format [new file with mode: 0644]
fsplugin/.tx/config [new file with mode: 0644]
fsplugin/CMakeLists.txt [new file with mode: 0644]
fsplugin/FinderSync.h [new file with mode: 0644]
fsplugin/FinderSync.mm [new file with mode: 0644]
fsplugin/FinderSyncClient.h [new file with mode: 0644]
fsplugin/FinderSyncClient.mm [new file with mode: 0644]
fsplugin/Info.plist [new file with mode: 0644]
fsplugin/bg_BG.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/build.sh [new file with mode: 0755]
fsplugin/ca.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/cs_CZ.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/de_DE.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/el_GR.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/en.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/es.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/es_AR.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/es_MX.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/et_EE.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/fr_FR.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/he_IL.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/hu_HU.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/is.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/it.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/ja.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/ko_KR.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/lv.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/nb_NO.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/nl_BE.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/nl_NL.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/pl_PL.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/pt_BR.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/pt_PT.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/ru.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/seafile-findersync-arch.svg [new file with mode: 0644]
fsplugin/seafile-fsplugin.entitlements [new file with mode: 0644]
fsplugin/sk_SK.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/status-done.icns [new file with mode: 0644]
fsplugin/status-error.icns [new file with mode: 0644]
fsplugin/status-ignored.icns [new file with mode: 0644]
fsplugin/status-locked-by-me.icns [new file with mode: 0644]
fsplugin/status-locked.icns [new file with mode: 0644]
fsplugin/status-syncing.icns [new file with mode: 0644]
fsplugin/sv.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/tr.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/uk.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/zh_CN.lproj/Localizable.strings [new file with mode: 0644]
fsplugin/zh_TW.lproj/Localizable.strings [new file with mode: 0644]
i18n/seafile_bg_BG.ts [new file with mode: 0644]
i18n/seafile_ca.ts [new file with mode: 0644]
i18n/seafile_cs_CZ.ts [new file with mode: 0644]
i18n/seafile_de_DE.ts [new file with mode: 0644]
i18n/seafile_el_GR.ts [new file with mode: 0644]
i18n/seafile_en.ts [new file with mode: 0644]
i18n/seafile_es.ts [new file with mode: 0644]
i18n/seafile_es_AR.ts [new file with mode: 0644]
i18n/seafile_es_MX.ts [new file with mode: 0644]
i18n/seafile_et_EE.ts [new file with mode: 0644]
i18n/seafile_fr_FR.ts [new file with mode: 0644]
i18n/seafile_he_IL.ts [new file with mode: 0644]
i18n/seafile_hu_HU.ts [new file with mode: 0644]
i18n/seafile_is.ts [new file with mode: 0644]
i18n/seafile_it.ts [new file with mode: 0644]
i18n/seafile_ja.ts [new file with mode: 0644]
i18n/seafile_ko_KR.ts [new file with mode: 0644]
i18n/seafile_lv.ts [new file with mode: 0644]
i18n/seafile_nb_NO.ts [new file with mode: 0644]
i18n/seafile_nl_BE.ts [new file with mode: 0644]
i18n/seafile_nl_NL.ts [new file with mode: 0644]
i18n/seafile_pl_PL.ts [new file with mode: 0644]
i18n/seafile_pt_BR.ts [new file with mode: 0644]
i18n/seafile_pt_PT.ts [new file with mode: 0644]
i18n/seafile_ru.ts [new file with mode: 0644]
i18n/seafile_sk_SK.ts [new file with mode: 0644]
i18n/seafile_sv.ts [new file with mode: 0644]
i18n/seafile_tr.ts [new file with mode: 0644]
i18n/seafile_uk.ts [new file with mode: 0644]
i18n/seafile_zh_CN.ts [new file with mode: 0644]
i18n/seafile_zh_TW.ts [new file with mode: 0644]
images/account-256.png [new file with mode: 0644]
images/account-checked.png [new file with mode: 0644]
images/account-checked@2x.png [new file with mode: 0644]
images/account-else.png [new file with mode: 0644]
images/account-else@2x.png [new file with mode: 0644]
images/account-settings.png [new file with mode: 0644]
images/account-settings@2x.png [new file with mode: 0644]
images/account.png [new file with mode: 0644]
images/account@2x.png [new file with mode: 0644]
images/add-account.png [new file with mode: 0644]
images/add-account@2x.png [new file with mode: 0644]
images/cancel.png [new file with mode: 0644]
images/cancel@2x.png [new file with mode: 0644]
images/clock.png [new file with mode: 0644]
images/clock@2x.png [new file with mode: 0644]
images/cloud-gray.png [new file with mode: 0644]
images/cloud-gray@2x.png [new file with mode: 0644]
images/daemon_down.png [new file with mode: 0644]
images/daemon_up.png [new file with mode: 0644]
images/delete-account.png [new file with mode: 0644]
images/delete-account@2x.png [new file with mode: 0644]
images/disk@2x.png [new file with mode: 0644]
images/download-48.png [new file with mode: 0644]
images/filebrowser/add.png [new file with mode: 0755]
images/filebrowser/add@2x.png [new file with mode: 0755]
images/filebrowser/backward.png [new file with mode: 0644]
images/filebrowser/backward@2x.png [new file with mode: 0644]
images/filebrowser/down-arrow.png [new file with mode: 0644]
images/filebrowser/forward.png [new file with mode: 0644]
images/filebrowser/forward@2x.png [new file with mode: 0644]
images/filebrowser/home.png [new file with mode: 0755]
images/filebrowser/home@2x.png [new file with mode: 0755]
images/filebrowser/locked-by-me.png [new file with mode: 0755]
images/filebrowser/locked-by-me@2x.png [new file with mode: 0755]
images/filebrowser/locked.png [new file with mode: 0755]
images/filebrowser/locked@2x.png [new file with mode: 0755]
images/filebrowser/path-separator.png [new file with mode: 0755]
images/filebrowser/path-separator@2x.png [new file with mode: 0755]
images/filebrowser/refresh-gray.png [new file with mode: 0755]
images/filebrowser/refresh-gray@2x.png [new file with mode: 0755]
images/filebrowser/settings.png [new file with mode: 0644]
images/filebrowser/settings@2x.png [new file with mode: 0644]
images/filebrowser/up-arrow.png [new file with mode: 0644]
images/files/file_audio.png [new file with mode: 0644]
images/files/file_audio@2x.png [new file with mode: 0644]
images/files/file_folder.png [new file with mode: 0644]
images/files/file_folder@2x.png [new file with mode: 0644]
images/files/file_folder_readonly.png [new file with mode: 0644]
images/files/file_folder_readonly@2x.png [new file with mode: 0644]
images/files/file_image.png [new file with mode: 0644]
images/files/file_image@2x.png [new file with mode: 0644]
images/files/file_ms_excel.png [new file with mode: 0644]
images/files/file_ms_excel@2x.png [new file with mode: 0644]
images/files/file_ms_ppt.png [new file with mode: 0644]
images/files/file_ms_ppt@2x.png [new file with mode: 0644]
images/files/file_ms_word.png [new file with mode: 0644]
images/files/file_ms_word@2x.png [new file with mode: 0644]
images/files/file_pdf.png [new file with mode: 0644]
images/files/file_pdf@2x.png [new file with mode: 0644]
images/files/file_text.png [new file with mode: 0644]
images/files/file_text@2x.png [new file with mode: 0644]
images/files/file_unknown.png [new file with mode: 0644]
images/files/file_unknown@2x.png [new file with mode: 0644]
images/files/file_video.png [new file with mode: 0644]
images/files/file_video@2x.png [new file with mode: 0644]
images/files/file_zip.png [new file with mode: 0644]
images/files/file_zip@2x.png [new file with mode: 0644]
images/files_v2/file_audio.png [new file with mode: 0644]
images/files_v2/file_audio@2x.png [new file with mode: 0755]
images/files_v2/file_folder.png [new file with mode: 0644]
images/files_v2/file_folder@2x.png [new file with mode: 0755]
images/files_v2/file_folder_readonly.png [new file with mode: 0755]
images/files_v2/file_folder_readonly@2x.png [new file with mode: 0755]
images/files_v2/file_image.png [new file with mode: 0644]
images/files_v2/file_image@2x.png [new file with mode: 0755]
images/files_v2/file_ms_excel.png [new file with mode: 0644]
images/files_v2/file_ms_excel@2x.png [new file with mode: 0755]
images/files_v2/file_ms_ppt.png [new file with mode: 0644]
images/files_v2/file_ms_ppt@2x.png [new file with mode: 0755]
images/files_v2/file_ms_word.png [new file with mode: 0644]
images/files_v2/file_ms_word@2x.png [new file with mode: 0755]
images/files_v2/file_pdf.png [new file with mode: 0644]
images/files_v2/file_pdf@2x.png [new file with mode: 0755]
images/files_v2/file_text.png [new file with mode: 0644]
images/files_v2/file_text@2x.png [new file with mode: 0755]
images/files_v2/file_unknown.png [new file with mode: 0644]
images/files_v2/file_unknown@2x.png [new file with mode: 0755]
images/files_v2/file_video.png [new file with mode: 0644]
images/files_v2/file_video@2x.png [new file with mode: 0755]
images/files_v2/file_zip.png [new file with mode: 0644]
images/files_v2/file_zip@2x.png [new file with mode: 0644]
images/folder.png [new file with mode: 0644]
images/info-gray.png [new file with mode: 0644]
images/info-gray@2x.png [new file with mode: 0644]
images/info.png [new file with mode: 0644]
images/leave-share.png [new file with mode: 0644]
images/leave-share@2x.png [new file with mode: 0644]
images/library-256.png [new file with mode: 0644]
images/loading-spinner.gif [new file with mode: 0755]
images/logout.png [new file with mode: 0644]
images/logout@2x.png [new file with mode: 0644]
images/mac/daemon_down.png [new file with mode: 0644]
images/mac/daemon_down@2x.png [new file with mode: 0644]
images/mac/daemon_down_white.png [new file with mode: 0644]
images/mac/daemon_down_white@2x.png [new file with mode: 0644]
images/mac/daemon_up.png [new file with mode: 0644]
images/mac/daemon_up@2x.png [new file with mode: 0644]
images/mac/daemon_up_white.png [new file with mode: 0644]
images/mac/daemon_up_white@2x.png [new file with mode: 0644]
images/mac/notification.png [new file with mode: 0644]
images/mac/notification@2x.png [new file with mode: 0644]
images/mac/notification_white.png [new file with mode: 0644]
images/mac/seafile_auto_sync_disabled.png [new file with mode: 0644]
images/mac/seafile_auto_sync_disabled@2x.png [new file with mode: 0644]
images/mac/seafile_auto_sync_disabled_white.png [new file with mode: 0644]
images/mac/seafile_auto_sync_disabled_white@2x.png [new file with mode: 0644]
images/mac/seafile_transfer_1.png [new file with mode: 0644]
images/mac/seafile_transfer_1_white.png [new file with mode: 0644]
images/mac/seafile_transfer_2.png [new file with mode: 0644]
images/mac/seafile_transfer_2_white.png [new file with mode: 0644]
images/mac/seafile_warning.png [new file with mode: 0644]
images/mac/seafile_warning@2x.png [new file with mode: 0644]
images/mac/seafile_warning_white.png [new file with mode: 0644]
images/mac/seafile_warning_white@2x.png [new file with mode: 0644]
images/main-panel/download.png [new file with mode: 0644]
images/main-panel/download@2x.png [new file with mode: 0644]
images/main-panel/folder.png [new file with mode: 0644]
images/main-panel/folder@2x.png [new file with mode: 0644]
images/main-panel/library-encrypted.png [new file with mode: 0644]
images/main-panel/library-encrypted@2x.png [new file with mode: 0644]
images/main-panel/library-normal.png [new file with mode: 0644]
images/main-panel/library-normal@2x.png [new file with mode: 0644]
images/main-panel/library-readonly.png [new file with mode: 0644]
images/main-panel/library-readonly@2x.png [new file with mode: 0644]
images/main-panel/network-error.png [new file with mode: 0644]
images/main-panel/network-error@2x.png [new file with mode: 0644]
images/main-panel/search-background.png [new file with mode: 0644]
images/main-panel/search-background@2x.png [new file with mode: 0644]
images/main-panel/sync.png [new file with mode: 0644]
images/main-panel/sync@2x.png [new file with mode: 0644]
images/main-panel/upload.png [new file with mode: 0644]
images/main-panel/upload@2x.png [new file with mode: 0644]
images/minus-gray.png [new file with mode: 0644]
images/minus-gray@2x.png [new file with mode: 0644]
images/notification.png [new file with mode: 0644]
images/pause-gray.png [new file with mode: 0644]
images/pause-gray@2x.png [new file with mode: 0644]
images/play-gray.png [new file with mode: 0644]
images/play-gray@2x.png [new file with mode: 0644]
images/remove-gray.png [new file with mode: 0644]
images/remove-gray@2x.png [new file with mode: 0644]
images/remove-red.png [new file with mode: 0644]
images/resync.png [new file with mode: 0644]
images/resync@2x.png [new file with mode: 0644]
images/seafile-24.png [new file with mode: 0644]
images/seafile-32.png [new file with mode: 0644]
images/seafile.png [new file with mode: 0644]
images/seafile_auto_sync_disabled.png [new file with mode: 0644]
images/seafile_transfer_1.png [new file with mode: 0644]
images/seafile_transfer_2.png [new file with mode: 0644]
images/seafile_warning.png [new file with mode: 0644]
images/share.png [new file with mode: 0644]
images/share@2x.png [new file with mode: 0644]
images/svg/account.svg [new file with mode: 0644]
images/svg/arrow.svg [new file with mode: 0644]
images/svg/caret-down.svg [new file with mode: 0644]
images/svg/caret-right.svg [new file with mode: 0644]
images/svg/caret-up.svg [new file with mode: 0644]
images/svg/clock.svg [new file with mode: 0644]
images/svg/close.svg [new file with mode: 0644]
images/svg/cloud.svg [new file with mode: 0644]
images/svg/disk.svg [new file with mode: 0644]
images/svg/download-alt.svg [new file with mode: 0644]
images/svg/exclamation.svg [new file with mode: 0644]
images/svg/folder-open.svg [new file with mode: 0644]
images/svg/info-sign.svg [new file with mode: 0644]
images/svg/link.svg [new file with mode: 0644]
images/svg/ok.svg [new file with mode: 0644]
images/svg/pause.svg [new file with mode: 0644]
images/svg/play.svg [new file with mode: 0644]
images/svg/plus.svg [new file with mode: 0644]
images/svg/question.svg [new file with mode: 0644]
images/svg/refresh.svg [new file with mode: 0644]
images/svg/repo.svg [new file with mode: 0644]
images/svg/rotate.svg [new file with mode: 0644]
images/svg/share.svg [new file with mode: 0644]
images/sync/cloud-sync.png [new file with mode: 0644]
images/sync/cloud-sync@2x.png [new file with mode: 0644]
images/sync/cloud-synced.png [new file with mode: 0644]
images/sync/cloud-synced@2x.png [new file with mode: 0644]
images/sync/cloud-unsynced.png [new file with mode: 0644]
images/sync/cloud-unsynced@2x.png [new file with mode: 0644]
images/sync/done.png [new file with mode: 0644]
images/sync/done@2x.png [new file with mode: 0644]
images/sync/exclamation.png [new file with mode: 0755]
images/sync/minus-sign.png [new file with mode: 0755]
images/sync/pause.png [new file with mode: 0755]
images/sync/pause@2x.png [new file with mode: 0755]
images/sync/question.png [new file with mode: 0755]
images/sync/status-done.png [new file with mode: 0644]
images/sync/status-done@2x.png [new file with mode: 0644]
images/sync/status-syncing.png [new file with mode: 0644]
images/sync/status-syncing@2x.png [new file with mode: 0644]
images/sync/waiting.png [new file with mode: 0755]
images/sync/waiting@2x.png [new file with mode: 0755]
images/sync_now-gray.png [new file with mode: 0644]
images/sync_now-gray@2x.png [new file with mode: 0644]
images/tabs/highlighted/history-orange.png [new file with mode: 0644]
images/tabs/highlighted/history-orange@2x.png [new file with mode: 0644]
images/tabs/highlighted/library-orange.png [new file with mode: 0644]
images/tabs/highlighted/library-orange@2x.png [new file with mode: 0644]
images/tabs/highlighted/search-orange.png [new file with mode: 0644]
images/tabs/highlighted/search-orange@2x.png [new file with mode: 0644]
images/tabs/highlighted/star-orange.png [new file with mode: 0644]
images/tabs/highlighted/star-orange@2x.png [new file with mode: 0644]
images/tabs/history-normal.png [new file with mode: 0644]
images/tabs/history-normal@2x.png [new file with mode: 0644]
images/tabs/library-normal.png [new file with mode: 0644]
images/tabs/library-normal@2x.png [new file with mode: 0644]
images/tabs/search-normal.png [new file with mode: 0644]
images/tabs/search-normal@2x.png [new file with mode: 0644]
images/tabs/star-normal.png [new file with mode: 0644]
images/tabs/star-normal@2x.png [new file with mode: 0644]
images/toolbar/add-gray.png [new file with mode: 0644]
images/toolbar/add-gray@2x.png [new file with mode: 0644]
images/toolbar/add.png [new file with mode: 0644]
images/toolbar/add@2x.png [new file with mode: 0644]
images/toolbar/download-gray.png [new file with mode: 0644]
images/toolbar/download-gray@2x.png [new file with mode: 0644]
images/toolbar/download.png [new file with mode: 0644]
images/toolbar/download@2x.png [new file with mode: 0644]
images/toolbar/file-gray.png [new file with mode: 0644]
images/toolbar/file-gray@2x.png [new file with mode: 0644]
images/toolbar/file.png [new file with mode: 0644]
images/toolbar/file@2x.png [new file with mode: 0644]
images/toolbar/refresh-gray.png [new file with mode: 0644]
images/toolbar/refresh-gray@2x.png [new file with mode: 0644]
images/toolbar/refresh-new.png [new file with mode: 0644]
images/toolbar/refresh-new@2x.png [new file with mode: 0644]
images/toolbar/refresh-orange.png [new file with mode: 0755]
images/toolbar/refresh-orange@2x.png [new file with mode: 0755]
images/toolbar/refresh.png [new file with mode: 0644]
images/toolbar/refresh@2x.png [new file with mode: 0644]
images/win/daemon_down.ico [new file with mode: 0644]
images/win/daemon_up.ico [new file with mode: 0644]
images/win/notification.ico [new file with mode: 0644]
images/win/seafile_auto_sync_disabled.ico [new file with mode: 0644]
images/win/seafile_transfer_1.ico [new file with mode: 0644]
images/win/seafile_transfer_2.ico [new file with mode: 0644]
images/win/seafile_warning.ico [new file with mode: 0644]
qt-linux.css [new file with mode: 0644]
qt-mac.css [new file with mode: 0644]
qt-win.css [new file with mode: 0644]
qt.css [new file with mode: 0644]
scripts/build.py [new file with mode: 0755]
scripts/build_breakpad.sh [new file with mode: 0755]
scripts/build_helper.py [new file with mode: 0755]
scripts/ci-build.sh [new file with mode: 0755]
scripts/genapp.sh [new file with mode: 0755]
scripts/install-deps-linux.sh [new file with mode: 0755]
scripts/install-deps-osx.sh [new file with mode: 0755]
scripts/strip-png.sh [new file with mode: 0755]
scripts/update-i18n.sh [new file with mode: 0755]
seafile-applet.rc.in [new file with mode: 0644]
seafile-client.qrc [new file with mode: 0644]
seafile.icns [new file with mode: 0644]
seafile.ico [new file with mode: 0644]
sparkle-readme.md [new file with mode: 0644]
src/account-info-service.cpp [new file with mode: 0644]
src/account-info-service.h [new file with mode: 0644]
src/account-mgr.cpp [new file with mode: 0644]
src/account-mgr.h [new file with mode: 0644]
src/account.cpp [new file with mode: 0644]
src/account.h [new file with mode: 0644]
src/api/api-client.cpp [new file with mode: 0644]
src/api/api-client.h [new file with mode: 0644]
src/api/api-error.cpp [new file with mode: 0644]
src/api/api-error.h [new file with mode: 0644]
src/api/api-request.cpp [new file with mode: 0644]
src/api/api-request.h [new file with mode: 0644]
src/api/commit-details.cpp [new file with mode: 0644]
src/api/commit-details.h [new file with mode: 0644]
src/api/contact-share-info.cpp [new file with mode: 0644]
src/api/contact-share-info.h [new file with mode: 0644]
src/api/event.cpp [new file with mode: 0644]
src/api/event.h [new file with mode: 0644]
src/api/requests.cpp [new file with mode: 0644]
src/api/requests.h [new file with mode: 0644]
src/api/server-info.h [new file with mode: 0644]
src/api/server-repo.cpp [new file with mode: 0644]
src/api/server-repo.h [new file with mode: 0644]
src/api/starred-file.cpp [new file with mode: 0644]
src/api/starred-file.h [new file with mode: 0644]
src/application.cpp [new file with mode: 0644]
src/application.h [new file with mode: 0644]
src/auto-login-service.cpp [new file with mode: 0644]
src/auto-login-service.h [new file with mode: 0644]
src/auto-update-service.cpp [new file with mode: 0644]
src/auto-update-service.h [new file with mode: 0644]
src/avatar-service.cpp [new file with mode: 0644]
src/avatar-service.h [new file with mode: 0644]
src/certs-mgr.cpp [new file with mode: 0644]
src/certs-mgr.h [new file with mode: 0644]
src/configurator.cpp [new file with mode: 0644]
src/configurator.h [new file with mode: 0644]
src/crash-handler.cpp [new file with mode: 0644]
src/crash-handler.h [new file with mode: 0644]
src/customization-service.cpp [new file with mode: 0644]
src/customization-service.h [new file with mode: 0644]
src/daemon-mgr.cpp [new file with mode: 0644]
src/daemon-mgr.h [new file with mode: 0644]
src/events-service.cpp [new file with mode: 0644]
src/events-service.h [new file with mode: 0644]
src/ext-handler.cpp [new file with mode: 0644]
src/ext-handler.h [new file with mode: 0644]
src/filebrowser/auto-update-mgr.cpp [new file with mode: 0644]
src/filebrowser/auto-update-mgr.h [new file with mode: 0644]
src/filebrowser/data-cache.cpp [new file with mode: 0644]
src/filebrowser/data-cache.h [new file with mode: 0644]
src/filebrowser/data-mgr.cpp [new file with mode: 0644]
src/filebrowser/data-mgr.h [new file with mode: 0644]
src/filebrowser/file-browser-dialog.cpp [new file with mode: 0644]
src/filebrowser/file-browser-dialog.h [new file with mode: 0644]
src/filebrowser/file-browser-manager.cpp [new file with mode: 0644]
src/filebrowser/file-browser-manager.h [new file with mode: 0644]
src/filebrowser/file-browser-requests.cpp [new file with mode: 0644]
src/filebrowser/file-browser-requests.h [new file with mode: 0644]
src/filebrowser/file-browser-search-tab.cpp [new file with mode: 0644]
src/filebrowser/file-browser-search-tab.h [new file with mode: 0644]
src/filebrowser/file-table.cpp [new file with mode: 0644]
src/filebrowser/file-table.h [new file with mode: 0644]
src/filebrowser/progress-dialog.cpp [new file with mode: 0644]
src/filebrowser/progress-dialog.h [new file with mode: 0644]
src/filebrowser/reliable-upload.cpp [new file with mode: 0644]
src/filebrowser/reliable-upload.h [new file with mode: 0644]
src/filebrowser/seaf-dirent.cpp [new file with mode: 0644]
src/filebrowser/seaf-dirent.h [new file with mode: 0644]
src/filebrowser/seafilelink-dialog.cpp [new file with mode: 0644]
src/filebrowser/seafilelink-dialog.h [new file with mode: 0644]
src/filebrowser/sharedlink-dialog.cpp [new file with mode: 0644]
src/filebrowser/sharedlink-dialog.h [new file with mode: 0644]
src/filebrowser/tasks.cpp [new file with mode: 0644]
src/filebrowser/tasks.h [new file with mode: 0644]
src/filebrowser/thumbnail-service.cpp [new file with mode: 0644]
src/filebrowser/thumbnail-service.h [new file with mode: 0644]
src/filebrowser/transfer-mgr.cpp [new file with mode: 0644]
src/filebrowser/transfer-mgr.h [new file with mode: 0644]
src/finder-sync/finder-sync-host.cpp [new file with mode: 0644]
src/finder-sync/finder-sync-host.h [new file with mode: 0644]
src/finder-sync/finder-sync-listener.h [new file with mode: 0644]
src/finder-sync/finder-sync-listener.mm [new file with mode: 0644]
src/finder-sync/finder-sync.cpp [new file with mode: 0644]
src/finder-sync/finder-sync.h [new file with mode: 0644]
src/i18n.cpp [new file with mode: 0644]
src/i18n.h [new file with mode: 0644]
src/log-uploader.cpp [new file with mode: 0644]
src/log-uploader.h [new file with mode: 0644]
src/mac-sparkle-support.h [new file with mode: 0644]
src/mac-sparkle-support.mm [new file with mode: 0644]
src/main.cpp [new file with mode: 0644]
src/message-poller.cpp [new file with mode: 0644]
src/message-poller.h [new file with mode: 0644]
src/network-mgr.cpp [new file with mode: 0644]
src/network-mgr.h [new file with mode: 0644]
src/open-local-helper.cpp [new file with mode: 0644]
src/open-local-helper.h [new file with mode: 0644]
src/repo-service-helper.cpp [new file with mode: 0644]
src/repo-service-helper.h [new file with mode: 0644]
src/repo-service.cpp [new file with mode: 0644]
src/repo-service.h [new file with mode: 0644]
src/rpc/clone-task.cpp [new file with mode: 0644]
src/rpc/clone-task.h [new file with mode: 0644]
src/rpc/local-repo.cpp [new file with mode: 0644]
src/rpc/local-repo.h [new file with mode: 0644]
src/rpc/rpc-client.cpp [new file with mode: 0644]
src/rpc/rpc-client.h [new file with mode: 0644]
src/rpc/rpc-server.cpp [new file with mode: 0644]
src/rpc/rpc-server.h [new file with mode: 0644]
src/rpc/rpc_table.py [new file with mode: 0644]
src/rpc/searpc-marshal.h [new file with mode: 0644]
src/rpc/searpc-signature.h [new file with mode: 0644]
src/rpc/sync-error.cpp [new file with mode: 0644]
src/rpc/sync-error.h [new file with mode: 0644]
src/rpc/update_rpc_sigs.sh [new file with mode: 0755]
src/seafile-applet.cpp [new file with mode: 0644]
src/seafile-applet.h [new file with mode: 0644]
src/seahub-notifications-monitor.cpp [new file with mode: 0644]
src/seahub-notifications-monitor.h [new file with mode: 0644]
src/server-status-service.cpp [new file with mode: 0644]
src/server-status-service.h [new file with mode: 0644]
src/settings-mgr.cpp [new file with mode: 0644]
src/settings-mgr.h [new file with mode: 0644]
src/shib/shib-helper.h [new file with mode: 0644]
src/shib/shib-login-dialog.cpp [new file with mode: 0644]
src/shib/shib-login-dialog.h [new file with mode: 0644]
src/traynotificationmanager.cpp [new file with mode: 0644]
src/traynotificationmanager.h [new file with mode: 0644]
src/traynotificationwidget.cpp [new file with mode: 0644]
src/traynotificationwidget.h [new file with mode: 0644]
src/ui/about-dialog.cpp [new file with mode: 0644]
src/ui/about-dialog.h [new file with mode: 0644]
src/ui/account-settings-dialog.cpp [new file with mode: 0644]
src/ui/account-settings-dialog.h [new file with mode: 0644]
src/ui/account-view.cpp [new file with mode: 0644]
src/ui/account-view.h [new file with mode: 0644]
src/ui/activities-tab.cpp [new file with mode: 0644]
src/ui/activities-tab.h [new file with mode: 0644]
src/ui/check-repo-root-perm-dialog.cpp [new file with mode: 0644]
src/ui/check-repo-root-perm-dialog.h [new file with mode: 0644]
src/ui/clone-tasks-dialog.cpp [new file with mode: 0644]
src/ui/clone-tasks-dialog.h [new file with mode: 0644]
src/ui/clone-tasks-table-model.cpp [new file with mode: 0644]
src/ui/clone-tasks-table-model.h [new file with mode: 0644]
src/ui/clone-tasks-table-view.cpp [new file with mode: 0644]
src/ui/clone-tasks-table-view.h [new file with mode: 0644]
src/ui/cloud-view.cpp [new file with mode: 0644]
src/ui/cloud-view.h [new file with mode: 0644]
src/ui/create-repo-dialog.cpp [new file with mode: 0644]
src/ui/create-repo-dialog.h [new file with mode: 0644]
src/ui/download-repo-dialog.cpp [new file with mode: 0644]
src/ui/download-repo-dialog.h [new file with mode: 0644]
src/ui/event-details-dialog.cpp [new file with mode: 0644]
src/ui/event-details-dialog.h [new file with mode: 0644]
src/ui/event-details-tree.cpp [new file with mode: 0644]
src/ui/event-details-tree.h [new file with mode: 0644]
src/ui/events-list-view.cpp [new file with mode: 0644]
src/ui/events-list-view.h [new file with mode: 0644]
src/ui/init-seafile-dialog.cpp [new file with mode: 0644]
src/ui/init-seafile-dialog.h [new file with mode: 0644]
src/ui/init-vdrive-dialog.cpp [new file with mode: 0644]
src/ui/init-vdrive-dialog.h [new file with mode: 0644]
src/ui/loading-view.cpp [new file with mode: 0644]
src/ui/loading-view.h [new file with mode: 0644]
src/ui/login-dialog.cpp [new file with mode: 0644]
src/ui/login-dialog.h [new file with mode: 0644]
src/ui/logout-view.cpp [new file with mode: 0644]
src/ui/logout-view.h [new file with mode: 0644]
src/ui/main-window.cpp [new file with mode: 0644]
src/ui/main-window.h [new file with mode: 0644]
src/ui/private-share-dialog.cpp [new file with mode: 0644]
src/ui/private-share-dialog.h [new file with mode: 0644]
src/ui/proxy-style.cpp [new file with mode: 0644]
src/ui/proxy-style.h [new file with mode: 0644]
src/ui/repo-detail-dialog.cpp [new file with mode: 0644]
src/ui/repo-detail-dialog.h [new file with mode: 0644]
src/ui/repo-item-delegate.cpp [new file with mode: 0644]
src/ui/repo-item-delegate.h [new file with mode: 0644]
src/ui/repo-item.cpp [new file with mode: 0644]
src/ui/repo-item.h [new file with mode: 0644]
src/ui/repo-tree-model.cpp [new file with mode: 0644]
src/ui/repo-tree-model.h [new file with mode: 0644]
src/ui/repo-tree-view.cpp [new file with mode: 0644]
src/ui/repo-tree-view.h [new file with mode: 0644]
src/ui/repos-tab.cpp [new file with mode: 0644]
src/ui/repos-tab.h [new file with mode: 0644]
src/ui/seafile-tab-widget.cpp [new file with mode: 0644]
src/ui/seafile-tab-widget.h [new file with mode: 0644]
src/ui/search-bar.cpp [new file with mode: 0644]
src/ui/search-bar.h [new file with mode: 0644]
src/ui/search-tab-items.cpp [new file with mode: 0644]
src/ui/search-tab-items.h [new file with mode: 0644]
src/ui/search-tab.cpp [new file with mode: 0644]
src/ui/search-tab.h [new file with mode: 0644]
src/ui/server-status-dialog.cpp [new file with mode: 0644]
src/ui/server-status-dialog.h [new file with mode: 0644]
src/ui/set-repo-password-dialog.cpp [new file with mode: 0644]
src/ui/set-repo-password-dialog.h [new file with mode: 0644]
src/ui/settings-dialog.cpp [new file with mode: 0644]
src/ui/settings-dialog.h [new file with mode: 0644]
src/ui/ssl-confirm-dialog.cpp [new file with mode: 0644]
src/ui/ssl-confirm-dialog.h [new file with mode: 0644]
src/ui/starred-file-item-delegate.cpp [new file with mode: 0644]
src/ui/starred-file-item-delegate.h [new file with mode: 0644]
src/ui/starred-file-item.cpp [new file with mode: 0644]
src/ui/starred-file-item.h [new file with mode: 0644]
src/ui/starred-files-list-model.cpp [new file with mode: 0644]
src/ui/starred-files-list-model.h [new file with mode: 0644]
src/ui/starred-files-list-view.cpp [new file with mode: 0644]
src/ui/starred-files-list-view.h [new file with mode: 0644]
src/ui/starred-files-tab.cpp [new file with mode: 0644]
src/ui/starred-files-tab.h [new file with mode: 0644]
src/ui/sync-errors-dialog.cpp [new file with mode: 0644]
src/ui/sync-errors-dialog.h [new file with mode: 0644]
src/ui/tab-view.cpp [new file with mode: 0644]
src/ui/tab-view.h [new file with mode: 0644]
src/ui/tray-icon.cpp [new file with mode: 0644]
src/ui/tray-icon.h [new file with mode: 0644]
src/ui/two-factor-dialog.cpp [new file with mode: 0644]
src/ui/two-factor-dialog.h [new file with mode: 0644]
src/ui/uninstall-helper-dialog.cpp [new file with mode: 0644]
src/ui/uninstall-helper-dialog.h [new file with mode: 0644]
src/ui/user-name-completer.cpp [new file with mode: 0644]
src/ui/user-name-completer.h [new file with mode: 0644]
src/utils/api-utils.cpp [new file with mode: 0644]
src/utils/api-utils.h [new file with mode: 0644]
src/utils/file-utils.cpp [new file with mode: 0644]
src/utils/file-utils.h [new file with mode: 0644]
src/utils/json-utils.cpp [new file with mode: 0644]
src/utils/json-utils.h [new file with mode: 0644]
src/utils/log.c [new file with mode: 0644]
src/utils/log.h [new file with mode: 0644]
src/utils/paint-utils.cpp [new file with mode: 0644]
src/utils/paint-utils.h [new file with mode: 0644]
src/utils/process-linux.cpp [new file with mode: 0644]
src/utils/process-mac.cpp [new file with mode: 0644]
src/utils/process-win.cpp [new file with mode: 0644]
src/utils/process.h [new file with mode: 0644]
src/utils/registry.cpp [new file with mode: 0644]
src/utils/registry.h [new file with mode: 0644]
src/utils/rsa.cpp [new file with mode: 0644]
src/utils/rsa.h [new file with mode: 0644]
src/utils/singleton.h [new file with mode: 0644]
src/utils/stl.cpp [new file with mode: 0644]
src/utils/stl.h [new file with mode: 0644]
src/utils/translate-commit-desc.cpp [new file with mode: 0644]
src/utils/translate-commit-desc.h [new file with mode: 0644]
src/utils/uninstall-helpers.cpp [new file with mode: 0644]
src/utils/uninstall-helpers.h [new file with mode: 0644]
src/utils/utils-mac.h [new file with mode: 0644]
src/utils/utils-mac.mm [new file with mode: 0644]
src/utils/utils-win.cpp [new file with mode: 0644]
src/utils/utils-win.h [new file with mode: 0644]
src/utils/utils.cpp [new file with mode: 0644]
src/utils/utils.h [new file with mode: 0644]
tests/CMakeLists.txt [new file with mode: 0644]
tests/test_file-utils.cpp [new file with mode: 0644]
tests/test_file-utils.h [new file with mode: 0644]
tests/test_server-info.cpp [new file with mode: 0644]
tests/test_server-info.h [new file with mode: 0644]
tests/test_stl.cpp [new file with mode: 0644]
tests/test_stl.h [new file with mode: 0644]
tests/test_utils.cpp [new file with mode: 0644]
tests/test_utils.h [new file with mode: 0644]
third_party/QtAwesome/QtAwesome.cpp [new file with mode: 0644]
third_party/QtAwesome/QtAwesome.h [new file with mode: 0644]
third_party/QtAwesome/QtAwesome.qrc [new file with mode: 0644]
third_party/QtAwesome/fonts/fontawesome.ttf [new file with mode: 0755]
ui/about-dialog.ui [new file with mode: 0644]
ui/account-settings-dialog.ui [new file with mode: 0644]
ui/account-view.ui [new file with mode: 0644]
ui/clone-tasks-dialog.ui [new file with mode: 0644]
ui/cloud-view.ui [new file with mode: 0644]
ui/create-repo-dialog.ui [new file with mode: 0644]
ui/download-repo-dialog.ui [new file with mode: 0644]
ui/init-seafile-dialog.ui [new file with mode: 0644]
ui/init-vdrive-dialog.ui [new file with mode: 0644]
ui/login-dialog.ui [new file with mode: 0644]
ui/private-share-dialog.ui [new file with mode: 0644]
ui/repo-detail-dialog.ui [new file with mode: 0644]
ui/server-repo-item.ui [new file with mode: 0644]
ui/server-repos-view.ui [new file with mode: 0644]
ui/server-status-dialog.ui [new file with mode: 0644]
ui/set-repo-password-dialog.ui [new file with mode: 0644]
ui/settings-dialog.ui [new file with mode: 0644]
ui/ssl-confirm-dialog.ui [new file with mode: 0644]
ui/two-factor-dialog.ui [new file with mode: 0644]
ui/uninstall-helper-dialog.ui [new file with mode: 0644]
ui/welcome-dialog.ui [new file with mode: 0644]

diff --git a/.clang-format b/.clang-format
new file mode 100644 (file)
index 0000000..a189b1d
--- /dev/null
@@ -0,0 +1,113 @@
+---
+BasedOnStyle: Google
+
+# Good:
+#
+#   class Foo
+#   {
+#   public:
+#
+#     Foo() = default;
+#
+#   };
+#
+# Bad:
+#
+#   class Foo
+#   {
+#    public:
+#
+#     Foo() = default;
+#
+#   };
+#
+AccessModifierOffset: -4
+
+# Good:
+#
+#   clang = Clang(); // Comment 1
+#   format = Format(); // Comment 2
+#
+# Bad:
+#   clang = Clang();   // Comment 1
+#   format = Format(); // Comment 2
+#
+AlignTrailingComments: false
+AllowShortFunctionsOnASingleLine: false
+AllowShortBlocksOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+
+# Good:
+#
+#   void F(int first,
+#          int second,
+#          int third,
+#          int fourth,
+#          int fifth,
+#          int sixth,
+#          int seventh,
+#          int eighth) {}
+#
+# Bad:
+#
+#   void F(int first, int second, int third, int fourth, int fifth, int sixth,
+#          int seventh, int eighth) {}
+#
+BinPackParameters: false
+BinPackArguments: false
+
+# Like 'Attach', but break before braces on function, namespaces, class, struct
+# and union definitions.
+#
+BreakBeforeBraces: Linux
+
+# Good:
+#
+#   class Foo
+#   {
+#     public:
+#
+#     Foo()
+#       : first(1), second(2) {}
+#
+#   };
+#
+# Bad:
+#
+#   class Foo
+#   {
+#     public:
+#
+#     Foo()
+#         : first(1), second(2) {}
+#
+#   };
+#
+ConstructorInitializerIndentWidth: 4
+IndentWidth:     4
+
+# Continuation indents such as assignment statements are indented by 2 spaces.
+ContinuationIndentWidth: 4
+
+PointerAlignment: Right
+# Don't try to guess the pointer alignment
+DerivePointerAlignment: false
+
+# List of foreach macros due to lack of range-based for loops.
+ForEachMacros: [ foreach, foreachkey, foreachvalue, foreachpair ]
+
+# Maximum number of empty lines to keep.
+MaxEmptyLinesToKeep: 2
+
+# Good:
+#
+#   x = 42; // Comment
+#
+# Bad:
+#
+#   x = 42;  // Comment
+#
+SpacesBeforeTrailingComments: 1
+...
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..bc8fba0
--- /dev/null
@@ -0,0 +1,107 @@
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.dll.a
+
+# executables
+seafile-applet
+orig-seafile-applet
+*.exe
+
+# backup file
+*#
+*~
+*.bak
+
+# other formats
+cscope*
+core
+*.pyc
+.DS_Store
+
+# CMake files goes here
+build/
+CMakeCache.txt
+CMakeFiles/
+Makefile
+cmake_install.cmake
+CTestTestfile.cmake
+Testing/
+install_manifest.txt
+
+#### Qt files goes here
+### moc
+moc_*.cxx*
+moc_*.cpp*
+*.moc
+
+### ui
+ui_*.h
+
+### qrc
+*.qrc.depends
+qrc_*.cxx
+qrc_*.cpp
+
+i18n/*.qm
+
+### emacs files
+.emacs*
+.#*
+
+### ninja files
+.ninja_deps
+.ninja_log
+build.ninja
+rules.ninja
+
+## xcode related
+Debug
+Release
+seafile-client.xcodeproj
+CMakeScripts
+seafile-applet.app
+seafile-fsplugin.xcodeproj
+Seafile FinderSync.appex
+
+## unittest related
+test_*
+!test_*.cpp
+!test_*.h
+
+## doxygen related
+docs
+Doxyfile
+
+## breakpad related
+third_party/gyp
+third_party/breakpad
+
+/GPATH
+/GTAGS
+/GRTAGS
+/gtags.files
+
+.deps
+compile_commands.json
+.ycm_extra_conf.py
+seafile-applet.rc
+*.dmp
+
+*seafile-applet
+*.lib
+
+## vscode
+.vscode/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..2755761
--- /dev/null
@@ -0,0 +1,27 @@
+sudo: required
+dist: trusty
+language: cpp
+matrix:
+  include:
+    - os: linux
+      compiler: gcc
+      env: BUILD_SHIBBOLETH_SUPPORT=ON
+    - os: linux
+      compiler: gcc
+      env: BUILD_SHIBBOLETH_SUPPORT=OFF
+  exclude:
+    - os: osx
+      compiler: gcc
+before_install:
+ - ./scripts/install-deps-${TRAVIS_OS_NAME}.sh
+script:
+ - ./scripts/ci-build.sh
+notifications:
+  email:
+    recipients:
+      - linshuai2012@gmail.com
+      - rwindz0@gmail.com
+  slack:
+    secure: RhwjY2BL0bR6MD+ASvFptH9GJmT0CshRN4YoZgK80D/H1kK60nVjfYIwU0apmhG8J3Sz9jqQ5xGPBUXvAgKB9VzdGQVgo23kGm9P2AY6xM43HHcPJvuXEBeX6zCx1O2HyGmENq36Z9ZnDWxW9yswnXKmeb05lE+PisBn1XvWQrs=
+    on_success: change
+    on_failure: always
diff --git a/.tx/config b/.tx/config
new file mode 100644 (file)
index 0000000..00a636b
--- /dev/null
@@ -0,0 +1,9 @@
+[main]
+host = https://www.transifex.com
+
+[seafile-client.master]
+file_filter = i18n/seafile_<lang>.ts
+source_file = i18n/seafile_en.ts
+source_lang = en
+type = TS
+
diff --git a/Application.manifest b/Application.manifest
new file mode 100644 (file)
index 0000000..f0f460c
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"/>
+    </dependentAssembly>
+  </dependency>
+</assembly>
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..206debc
--- /dev/null
@@ -0,0 +1,863 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9)
+
+PROJECT(seafile-client)
+SET(SEAFILE_CLIENT_VERSION_MAJOR 7)
+SET(SEAFILE_CLIENT_VERSION_MINOR 0)
+SET(SEAFILE_CLIENT_VERSION_PATCH 2)
+SET(PROJECT_VERSION "${SEAFILE_CLIENT_VERSION_MAJOR}.${SEAFILE_CLIENT_VERSION_MINOR}.${SEAFILE_CLIENT_VERSION_PATCH}")
+ADD_DEFINITIONS(-DSEAFILE_CLIENT_VERSION=${PROJECT_VERSION})
+INCLUDE(FindPkgConfig)
+
+## Build crash repoter on release build as default
+IF (NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
+  SET(CMAKE_BUILD_TYPE Debug)
+ENDIF()
+
+# CMake's builtin UNIX variable is true on Mac/Linux/BSD, but sometimes we want
+# to detect for LINUX.
+IF (UNIX AND NOT APPLE)
+  SET(LINUX TRUE)
+ENDIF()
+
+IF (APPLE AND NOT CMAKE_OSX_DEPLOYMENT_TARGET)
+  SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.7")
+ENDIF()
+
+FIND_PROGRAM(git_executable NAMES git git.exe git.cmd)
+IF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git AND NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
+  EXECUTE_PROCESS(COMMAND
+    ${git_executable} rev-list HEAD --count
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+    OUTPUT_VARIABLE SEAFILE_CLIENT_REVISION
+    OUTPUT_STRIP_TRAILING_WHITESPACE )
+  ADD_DEFINITIONS(-DSEAFILE_CLIENT_REVISION=${SEAFILE_CLIENT_REVISION})
+ENDIF()
+
+SET(PATH_TO_BREAKPAD_ROOT CACHE "Path to breakpad's root" "")
+
+OPTION(BUILD_TESTING "Build Test" OFF)
+
+OPTION(BUILD_DOCS "Build Documents" OFF)
+
+OPTION(BUILD_SHIBBOLETH_SUPPORT "Build Shibboleth support" OFF)
+
+option(BUILD_ENABLE_WARNINGS "Enable compiler warnings." ON)
+
+option(BUILD_SPARKLE_SUPPORT "Build Sparkle support" OFF)
+IF (BUILD_SPARKLE_SUPPORT)
+    ADD_DEFINITIONS(-DHAVE_SPARKLE_SUPPORT)
+    IF (LINUX)
+      message(FATAL_ERROR "Sparkle Support is not available for linux." )
+    ENDIF()
+    SET(platform_specific_moc_headers ${platform_specific_moc_headers} src/auto-update-service.h)
+    SET(platform_specific_sources ${platform_specific_sources} src/auto-update-service.cpp)
+    IF (NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
+        ADD_DEFINITIONS(-DSEAFILE_SPARKLE_DEBUG)
+    ENDIF()
+ENDIF()
+
+MESSAGE("Build type: ${CMAKE_BUILD_TYPE}")
+
+## build in PIC mode
+IF (NOT WIN32)
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
+ENDIF()
+
+## Setup warnings ouput if enabled
+## but don't warning on unsupported warnings
+if(BUILD_ENABLE_WARNINGS)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wsign-compare -Wno-long-long -Wno-unused-parameter")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wsign-compare -Wno-long-long -Wno-unused-parameter -Woverloaded-virtual")
+  if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unknown-warning-option")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option -Wno-inconsistent-missing-override")
+  endif()
+endif()
+
+## color diagnostics fix
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcolor-diagnostics")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+  execute_process(COMMAND ${CMAKE_CXX_COMPILER}
+    -dumpversion OUTPUT_VARIABLE GCC_VERSION)
+  if(GCC_VERSION VERSION_GREATER 4.9 OR GCC_VERSION VERSION_EQUAL 4.9)
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always")
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
+  endif()
+endif()
+
+IF (WIN32)
+    CONFIGURE_FILE(
+      ${CMAKE_SOURCE_DIR}/seafile-applet.rc.in
+      ${CMAKE_BINARY_DIR}/seafile-applet.rc
+    )
+    SET(EXTRA_LIBS ${EXTRA_LIBS} psapi ws2_32 shlwapi mpr crypt32)
+    SET(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_BINARY_DIR}/seafile-applet.rc)
+    IF (${CMAKE_BUILD_TYPE} MATCHES Release)
+      SET(GUI_TYPE WIN32)
+    ENDIF()
+    SET(platform_specific_moc_headers ${platform_specific_moc_headers} src/ext-handler.h)
+    SET(platform_specific_sources ${platform_specific_sources} src/ext-handler.cpp)
+    IF (BUILD_SPARKLE_SUPPORT)
+      IF(NOT EXISTS "${CMAKE_SOURCE_DIR}/WinSparkle.lib")
+        message(FATAL_ERROR "File ${CMAKE_SOURCE_DIR}/WinSparkle.lib not found in current directory. Please setup winsparkle correctly." )
+      ENDIF()
+      SET(SPARKLE_LIBS ${CMAKE_SOURCE_DIR}/WinSparkle.lib)
+    ENDIF()
+
+ELSEIF (LINUX)
+    INCLUDE_DIRECTORIES(${QT_QTDBUS_INCLUDE_DIR})
+    LINK_DIRECTORIES(${QT_QTDBUS_LIBRARIES})
+    SET(EXTRA_LIBS ${EXTRA_LIBS} ${QT_QTDBUS_LIBRARIES})
+ELSEIF (APPLE)
+    IF (BUILD_SPARKLE_SUPPORT)
+        SET(platform_specific_sources ${platform_specific_sources} src/mac-sparkle-support.mm)
+        SET_SOURCE_FILES_PROPERTIES(src/mac-sparkle-support.mm
+          PROPERTIES COMPILE_FLAGS -fobjc-arc)
+
+        SET(SPARKLE_FRAMEWORK /usr/local/Sparkle.framework)
+        IF(NOT EXISTS "${SPARKLE_FRAMEWORK}")
+          message(FATAL_ERROR "File ${SPARKLE_FRAMEWORK} not found. Please setup it correctly.")
+        ENDIF()
+        INCLUDE_DIRECTORIES(${SPARKLE_FRAMEWORK}/Headers)
+        SET(EXTRA_LIBS ${EXTRA_LIBS} ${SPARKLE_FRAMEWORK})
+    ENDIF()
+
+    SET(platform_specific_sources ${platform_specific_sources} src/application.cpp)
+    ## Enforce ARC for this file, since ARC is only supported after the objc
+    ## runtime changes in os x 10.10
+    SET_SOURCE_FILES_PROPERTIES(src/utils/utils-mac.mm
+      PROPERTIES COMPILE_FLAGS -fobjc-arc)
+
+    FIND_LIBRARY(COCOA_LIBRARY Cocoa)
+    MARK_AS_ADVANCED (COCOA_LIBRARY)
+    FIND_LIBRARY(Sec_LIBRARY Security)
+    MARK_AS_ADVANCED (Sec_LIBRARY)
+    SET(EXTRA_LIBS ${EXTRA_LIBS} ${COCOA_LIBRARY} ${Sec_LIBRARY})
+ENDIF()
+
+IF(APPLE)
+    ADD_DEFINITIONS(-DHAVE_FINDER_SYNC_SUPPORT)
+    SET(platform_specific_moc_headers ${platform_specific_moc_headers} src/finder-sync/finder-sync-host.h)
+    SET(platform_specific_sources ${platform_specific_sources}
+        src/finder-sync/finder-sync.cpp src/finder-sync/finder-sync-listener.mm
+        src/finder-sync/finder-sync-host.cpp)
+    SET_SOURCE_FILES_PROPERTIES(src/finder-sync/finder-sync-listener.mm
+        PROPERTIES COMPILE_FLAGS -fobjc-arc)
+ENDIF()
+
+####################
+###### BEGIN: QT configuration
+####################
+SET(QT_VERSION_MAJOR 5)
+
+# Qt 5.6.0 removes QtWebKit, we need to use QtWebEnigne. First we detect the
+# current qt version, then use proper name based on the version. However we
+# have to keep using QtWebKit on windows because QtWebEngine can't be
+# compiled in msys2/mingw (QtWebEnigne is based on chrome, which has to be
+# compiled with MSVC.)
+FIND_PROGRAM(qmake_executable NAMES qmake qmake.exe)
+EXECUTE_PROCESS(COMMAND
+    bash -c "${qmake_executable} --version | grep -iE '^using qt version [0-9.]+' | awk '{print $4}'"
+    OUTPUT_VARIABLE DETECTED_QT_VERSION
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+MESSAGE("qt5 version: ${DETECTED_QT_VERSION}")
+IF(WIN32 OR DETECTED_QT_VERSION VERSION_LESS 5.6.0)
+    ADD_DEFINITIONS(-DSEAFILE_USE_WEBKIT)
+    SET(WEBKIT_NAME "WebKit")
+    SET(WEBKIT_WIDGETS_NAME "WebKitWidgets")
+ELSE()
+    SET(WEBKIT_NAME "WebEngine")
+    SET(WEBENGINE_CORE "WebEngineCore")
+    SET(WEBKIT_WIDGETS_NAME "WebEngineWidgets")
+    SET(SHIB_EXTRA_HEADER "src/shib/shib-helper.h")
+ENDIF()
+
+SET(USE_QT_LIBRARIES
+    Core Gui Widgets LinguistTools Network
+    )
+IF (BUILD_SHIBBOLETH_SUPPORT)
+    SET(USE_QT_LIBRARIES ${USE_QT_LIBRARIES} ${WEBENGINE_CORE} ${WEBKIT_NAME} ${WEBKIT_WIDGETS_NAME})
+    ADD_DEFINITIONS(-DHAVE_SHIBBOLETH_SUPPORT)
+ENDIF()
+
+IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+    SET(USE_QT_LIBRARIES ${USE_QT_LIBRARIES} "DBus")
+ENDIF()
+
+FIND_PACKAGE(Qt5 REQUIRED ${USE_QT_LIBRARIES})
+SET(QT_LUPDATE_EXECUTABLE ${Qt5_LUPDATE_EXECUTABLE})
+# from QT 5.4.0 Changelog
+# The Qt binary packages are now configured with C++11 enabled.
+# this requires your gcc compiler newer than 4.8.1 or clang newer than 3.3
+
+if (CYGWIN OR MINGW)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
+else()
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+endif()
+
+# for OS X, we requires libc++ instead
+if (APPLE)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+    SET(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
+    SET(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
+endif()
+
+ADD_DEFINITIONS(-DQUAZIP_STATIC)
+
+# MOC FILES
+SET(moc_headers
+  src/seafile-applet.h
+  src/account-mgr.h
+  src/configurator.h
+  src/daemon-mgr.h
+  src/auto-login-service.h
+  src/repo-service.h
+  src/repo-service-helper.h
+  src/events-service.h
+  src/avatar-service.h
+  src/open-local-helper.h
+  src/server-status-service.h
+  src/account-info-service.h
+  src/customization-service.h
+  src/message-poller.h
+  src/network-mgr.h
+  src/settings-mgr.h
+  src/traynotificationwidget.h
+  src/traynotificationmanager.h
+  src/log-uploader.h
+  src/api/api-client.h
+  src/api/api-request.h
+  src/api/requests.h
+  src/rpc/rpc-client.h
+  src/rpc/rpc-server.h
+  src/ui/main-window.h
+  src/ui/init-seafile-dialog.h
+  src/ui/login-dialog.h
+  src/ui/account-settings-dialog.h
+  src/ui/check-repo-root-perm-dialog.h
+  src/ui/create-repo-dialog.h
+  src/ui/repo-detail-dialog.h
+  src/ui/settings-dialog.h
+  src/ui/download-repo-dialog.h
+  src/ui/cloud-view.h
+  src/ui/tray-icon.h
+  src/ui/about-dialog.h
+  src/ui/repo-tree-model.h
+  src/ui/repo-tree-view.h
+  src/ui/repo-item-delegate.h
+  src/ui/clone-tasks-dialog.h
+  src/ui/clone-tasks-table-model.h
+  src/ui/clone-tasks-table-view.h
+  src/ui/server-status-dialog.h
+  src/ui/search-tab.h
+  src/ui/search-tab-items.h
+  src/ui/init-vdrive-dialog.h
+  src/ui/uninstall-helper-dialog.h
+  src/ui/ssl-confirm-dialog.h
+  src/ui/private-share-dialog.h
+  src/ui/user-name-completer.h
+  src/ui/account-view.h
+  src/ui/seafile-tab-widget.h
+  src/ui/tab-view.h
+  src/ui/loading-view.h
+  src/ui/logout-view.h
+  src/ui/repos-tab.h
+  src/ui/starred-files-tab.h
+  src/ui/starred-files-list-view.h
+  src/ui/starred-files-list-model.h
+  src/ui/starred-file-item-delegate.h
+  src/ui/activities-tab.h
+  src/ui/events-list-view.h
+  src/ui/event-details-dialog.h
+  src/ui/event-details-tree.h
+  src/ui/set-repo-password-dialog.h
+  src/ui/sync-errors-dialog.h
+  src/ui/search-bar.h
+  src/ui/two-factor-dialog.h
+  src/filebrowser/file-browser-manager.h
+  src/filebrowser/file-browser-dialog.h
+  src/filebrowser/file-browser-requests.h
+  src/filebrowser/file-browser-search-tab.h
+  src/filebrowser/file-table.h
+  src/filebrowser/data-mgr.h
+  src/filebrowser/tasks.h
+  src/filebrowser/reliable-upload.h
+  src/filebrowser/progress-dialog.h
+  src/filebrowser/sharedlink-dialog.h
+  src/filebrowser/seafilelink-dialog.h
+  src/filebrowser/auto-update-mgr.h
+  src/filebrowser/transfer-mgr.h
+  src/filebrowser/thumbnail-service.h
+  third_party/QtAwesome/QtAwesome.h
+  third_party/quazip/quazipfile.h
+  ${platform_specific_moc_headers}
+)
+
+IF (APPLE)
+  SET(moc_headers ${moc_headers} src/application.h)
+ENDIF()
+
+IF (BUILD_SHIBBOLETH_SUPPORT)
+  SET(moc_headers ${moc_headers} src/shib/shib-login-dialog.h ${SHIB_EXTRA_HEADER})
+ENDIF()
+
+# UI FILES
+SET(ui_files
+  ui/about-dialog.ui
+  ui/login-dialog.ui
+  ui/account-settings-dialog.ui
+  ui/create-repo-dialog.ui
+  ui/repo-detail-dialog.ui
+  ui/settings-dialog.ui
+  ui/download-repo-dialog.ui
+  ui/init-seafile-dialog.ui
+  ui/cloud-view.ui
+  ui/clone-tasks-dialog.ui
+  ui/server-status-dialog.ui
+  ui/init-vdrive-dialog.ui
+  ui/uninstall-helper-dialog.ui
+  ui/ssl-confirm-dialog.ui
+  ui/private-share-dialog.ui
+  ui/account-view.ui
+  ui/two-factor-dialog.ui
+  ui/set-repo-password-dialog.ui
+  ${platform_specific_ui_files}
+)
+
+# RESOURCES
+SET(qrc_files
+  seafile-client.qrc
+  third_party/QtAwesome/QtAwesome.qrc
+)
+
+QT5_WRAP_UI(ui_output ${ui_files})
+
+# meta object compliation(moc)
+QT5_WRAP_CPP(moc_output ${moc_headers})
+
+# resources files
+QT5_ADD_RESOURCES(resources_ouput ${qrc_files})
+
+# MESSAGE("moc output: ${moc_output}")
+# MESSAGE("ui output: ${ui_output}")
+
+####################
+###### END: QT configuration
+####################
+
+####################
+###### BEGIN: pthread support is required explicitly on linux
+####################
+
+IF(NOT WIN32 AND NOT APPLE)
+  SET(CMAKE_THREAD_PREFER_PTHREAD ON)
+  INCLUDE(FindThreads)
+  LINK_LIBRARIES(${CMAKE_THREAD_LIBS_INIT})
+ENDIF(NOT WIN32 AND NOT APPLE)
+
+####################
+###### BEGIN: other libraries configuration
+####################
+FIND_PACKAGE(PkgConfig REQUIRED)
+
+PKG_CHECK_MODULES(SQLITE3 REQUIRED sqlite3>=3.0.0)
+
+PKG_CHECK_MODULES(JANSSON REQUIRED jansson>=2.0)
+
+PKG_CHECK_MODULES(LIBSEARPC REQUIRED libsearpc>=1.0)
+
+PKG_CHECK_MODULES(OPENSSL REQUIRED openssl>=0.98)
+
+PKG_CHECK_MODULES(LIBSEAFILE REQUIRED libseafile>=1.7)
+
+PKG_CHECK_MODULES(LIBEVENT REQUIRED libevent>=2.0)
+
+PKG_CHECK_MODULES(ZLIB REQUIRED zlib>=1.2)
+####################
+###### END: other libraries configuration
+####################
+
+
+# c/cpp sources
+SET(seafile_client_sources
+  src/i18n.cpp
+  src/main.cpp
+  src/seafile-applet.cpp
+  src/account.cpp
+  src/account-mgr.cpp
+  src/daemon-mgr.cpp
+  src/configurator.cpp
+  src/open-local-helper.cpp
+  src/message-poller.cpp
+  src/network-mgr.cpp
+  src/auto-login-service.cpp
+  src/repo-service.cpp
+  src/repo-service-helper.cpp
+  src/events-service.cpp
+  src/server-status-service.cpp
+  src/account-info-service.cpp
+  src/customization-service.cpp
+  src/avatar-service.cpp
+  src/settings-mgr.cpp
+  src/traynotificationwidget.cpp
+  src/traynotificationmanager.cpp
+  src/certs-mgr.cpp
+  src/log-uploader.cpp
+  src/api/api-client.cpp
+  src/api/api-request.cpp
+  src/api/api-error.cpp
+  src/api/requests.cpp
+  src/api/server-repo.cpp
+  src/api/starred-file.cpp
+  src/api/event.cpp
+  src/api/commit-details.cpp
+  src/api/contact-share-info.cpp
+  src/rpc/rpc-client.cpp
+  src/rpc/rpc-server.cpp
+  src/rpc/local-repo.cpp
+  src/rpc/clone-task.cpp
+  src/rpc/sync-error.cpp
+  src/ui/about-dialog.cpp
+  src/ui/main-window.cpp
+  src/ui/init-seafile-dialog.cpp
+  src/ui/login-dialog.cpp
+  src/ui/account-settings-dialog.cpp
+  src/ui/check-repo-root-perm-dialog.cpp
+  src/ui/repo-detail-dialog.cpp
+  src/ui/settings-dialog.cpp
+  src/ui/create-repo-dialog.cpp
+  src/ui/download-repo-dialog.cpp
+  src/ui/tray-icon.cpp
+  src/ui/cloud-view.cpp
+  src/utils/uninstall-helpers.cpp
+  src/ui/repo-item.cpp
+  src/ui/repo-tree-model.cpp
+  src/ui/repo-tree-view.cpp
+  src/ui/repo-item-delegate.cpp
+  src/ui/clone-tasks-dialog.cpp
+  src/ui/clone-tasks-table-model.cpp
+  src/ui/clone-tasks-table-view.cpp
+  src/ui/server-status-dialog.cpp
+  src/ui/init-vdrive-dialog.cpp
+  src/ui/uninstall-helper-dialog.cpp
+  src/ui/search-tab.cpp
+  src/ui/search-tab-items.cpp
+  src/ui/ssl-confirm-dialog.cpp
+  src/ui/private-share-dialog.cpp
+  src/ui/user-name-completer.cpp
+  src/ui/proxy-style.cpp
+  src/ui/account-view.cpp
+  src/ui/seafile-tab-widget.cpp
+  src/ui/tab-view.cpp
+  src/ui/loading-view.cpp
+  src/ui/logout-view.cpp
+  src/ui/repos-tab.cpp
+  src/ui/starred-files-tab.cpp
+  src/ui/starred-files-list-view.cpp
+  src/ui/starred-files-list-model.cpp
+  src/ui/starred-file-item.cpp
+  src/ui/starred-file-item-delegate.cpp
+  src/ui/activities-tab.cpp
+  src/ui/events-list-view.cpp
+  src/ui/event-details-dialog.cpp
+  src/ui/event-details-tree.cpp
+  src/ui/set-repo-password-dialog.cpp
+  src/ui/sync-errors-dialog.cpp
+  src/ui/search-bar.cpp
+  src/ui/two-factor-dialog.cpp
+  src/filebrowser/file-browser-manager.cpp
+  src/filebrowser/file-browser-dialog.cpp
+  src/filebrowser/file-browser-requests.cpp
+  src/filebrowser/file-browser-search-tab.cpp
+  src/filebrowser/data-mgr.cpp
+  src/filebrowser/data-cache.cpp
+  src/filebrowser/file-table.cpp
+  src/filebrowser/seaf-dirent.cpp
+  src/filebrowser/reliable-upload.cpp
+  src/filebrowser/tasks.cpp
+  src/filebrowser/progress-dialog.cpp
+  src/filebrowser/sharedlink-dialog.cpp
+  src/filebrowser/seafilelink-dialog.cpp
+  src/filebrowser/auto-update-mgr.cpp
+  src/filebrowser/transfer-mgr.cpp
+  src/filebrowser/thumbnail-service.cpp
+  third_party/QtAwesome/QtAwesome.cpp
+  ${platform_specific_sources}
+)
+
+IF (BUILD_SHIBBOLETH_SUPPORT)
+  SET(seafile_client_sources ${seafile_client_sources} src/shib/shib-login-dialog.cpp)
+ENDIF()
+
+INCLUDE_DIRECTORIES(
+  ${CMAKE_CURRENT_SOURCE_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}/src
+  ${CMAKE_CURRENT_SOURCE_DIR}/third_party/QtAwesome
+  ${CMAKE_CURRENT_SOURCE_DIR}/third_party/quazip
+  )
+
+FOREACH(USE_QT_LIBRARY ${USE_QT_LIBRARIES})
+INCLUDE_DIRECTORIES(
+${Qt5${USE_QT_LIBRARY}_INCLUDE_DIRS}
+)
+ENDFOREACH()
+
+INCLUDE_DIRECTORIES(
+  ${OPENSSL_INCLUDE_DIRS}
+  ${LIBEVENT_INCLUDE_DIRS}
+  ${SQLITE3_INCLUDE_DIRS}
+  ${JANSSON_INCLUDE_DIRS}
+  ${LIBSEARPC_INCLUDE_DIRS}
+  ${LIBSEAFILE_INCLUDE_DIRS}
+)
+
+LINK_DIRECTORIES(
+  ${QT_LIBRARY_DIR}
+  ${OPENSSL_LIBRARY_DIRS}
+  ${LIBEVENT_LIBRARY_DIRS}
+  ${LIBSEAFILE_LIBRARY_DIRS}
+  ${LIBSEARPC_LIBRARY_DIRS}
+  ${SQLITE3_LIBRARRY_DIRS}
+  ${JANSSON_LIBRARRY_DIRS}
+  ${ZLIB_LIBRARRY_DIRS}
+)
+
+####################
+###### begin: lib
+####################
+
+# Helper Function to Add Seafile-Client Library
+# Usage:
+# ADD_SC_LIBRARY (name sources
+#     MOC_HEADERS moc_headers
+#     UI_FILES ui_files
+#     DEPENDS part
+#     LINK_LIBS libs
+#     )
+FUNCTION(ADD_SC_LIBRARY name)
+    MESSAGE(STATUS "Found internal library: ${name}")
+    CMAKE_PARSE_ARGUMENTS(ARG
+      ""
+      ""
+      "MOC_HEADERS;UI_FILES;DEPENDS;LINK_LIBS"
+      ${ARGN})
+    IF(ARG_MOC_HEADERS)
+        QT5_WRAP_CPP(MOC_OUTPUT ${ARG_MOC_HEADERS})
+    ENDIF()
+    IF(ARG_UI_FILES)
+        QT5_WRAP_UI(UI_OUTPUT ${ARG_UI_FILES})
+    ENDIF()
+
+    ADD_LIBRARY(${name} STATIC ${ARG_UNPARSED_ARGUMENTS}
+      ${MOC_OUTPUT} ${UI_OUTPUT})
+
+    TARGET_LINK_LIBRARIES(${name} ${QT_LIBRARIES}
+        ${SQLITE3_LIBRARIES} ${JANSSON_LIBRARIES}
+        ${EXTRA_LIBS} -lglib-2.0 ${ARG_LINK_LIBS} ${ZLIB_LIBRARIES})
+ENDFUNCTION(ADD_SC_LIBRARY)
+
+# library utils
+LIST(APPEND utils_sources
+    src/utils/utils.cpp
+    src/utils/rsa.cpp
+    src/utils/api-utils.cpp
+    src/utils/paint-utils.cpp
+    src/utils/file-utils.cpp
+    src/utils/translate-commit-desc.cpp
+    src/utils/json-utils.cpp
+    src/utils/log.c
+    src/utils/stl.cpp
+    )
+IF (WIN32)
+    LIST(APPEND utils_sources
+        src/utils/process-win.cpp
+        src/utils/registry.cpp
+        src/utils/utils-win.cpp
+        )
+ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "BSD")
+    LIST(APPEND utils_sources
+        src/utils/process-linux.cpp
+        )
+ELSEIF(APPLE)
+    LIST(APPEND utils_sources
+        src/utils/process-mac.cpp
+        src/utils/utils-mac.mm)
+ENDIF()
+
+ADD_SC_LIBRARY(utils ${utils_sources})
+
+# library quazip
+LIST(APPEND quazip_sources
+    third_party/quazip/JlCompress.cpp
+    third_party/quazip/quazip.cpp
+    third_party/quazip/quazipfile.cpp
+    third_party/quazip/quazipfileinfo.cpp
+    third_party/quazip/quaziodevice.cpp
+    third_party/quazip/quagzipfile.cpp
+    third_party/quazip/quazipnewinfo.cpp
+    third_party/quazip/quaadler32.cpp
+    third_party/quazip/quazipdir.cpp
+    third_party/quazip/quacrc32.cpp
+    third_party/quazip/qioapi.cpp
+    third_party/quazip/zip.c
+    third_party/quazip/unzip.c
+    )
+
+ADD_SC_LIBRARY(quazip ${quazip_sources})
+
+SET(SC_LIBS utils quazip)
+#SET(SC_LIBS utils)
+
+####################
+###### end: lib
+####################
+
+####################
+###### start: translations
+####################
+
+SET(SEAFILE_TRANSLATE_SOURCES ${seafile_client_sources} ${utils_sources} ${moc_output} ${ui_output})
+SET(LANGUAGES
+  ca
+  de_DE
+  en
+  es
+  es_AR
+  es_MX
+  fr_FR
+  he_IL
+  hu_HU
+  is
+  it
+  ko_KR
+  nl_BE
+  pl_PL
+  pt_BR
+  pt_PT
+  ru
+  sk_SK
+  uk
+  zh_CN
+  zh_TW
+  tr
+  nl_NL
+  lv
+  ja
+  sv
+  cs_CZ
+  el_GR
+  nb_NO
+  )
+
+SET(LANGUAGE_TS_FILES)
+SET(SEAFILE_TS_TARGETS)
+FOREACH(LANGUAGE ${LANGUAGES})
+  SET(TS_FILE "${PROJECT_SOURCE_DIR}/i18n/seafile_${LANGUAGE}.ts")
+  SET(LANGUAGE_TS_FILES ${LANGUAGE_TS_FILES} ${TS_FILE})
+  SET_SOURCE_FILES_PROPERTIES(${TS_FILE} PROPERTIES OUTPUT_LOCATION "${PROJECT_SOURCE_DIR}/i18n")
+
+  SET(TS_TARGET "${LANGUAGE}_ts")
+  ADD_CUSTOM_TARGET(${TS_TARGET}
+    COMMAND ${QT_LUPDATE_EXECUTABLE} ${SEAFILE_TRANSLATE_SOURCES}
+        -ts "${PROJECT_SOURCE_DIR}/i18n/seafile_${LANGUAGE}.ts"
+        -I "${PROJECT_SOURCE_DIR}/src"
+        -locations none
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
+
+  SET(SEAFILE_TS_TARGETS ${SEAFILE_TS_TARGETS} ${TS_TARGET})
+
+ENDFOREACH(LANGUAGE ${LANGUAGES})
+
+QT5_ADD_TRANSLATION(qm_files ${LANGUAGE_TS_FILES})
+
+ADD_CUSTOM_TARGET(update-ts DEPENDS ${SEAFILE_TS_TARGETS})
+
+####################
+###### end: translations
+####################
+
+###################
+##### begin: doxygen
+##################
+FIND_PACKAGE(Doxygen)
+
+IF (DOXYGEN_FOUND)
+  CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
+    ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+
+  ADD_CUSTOM_TARGET(doxygen
+    COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+    COMMENT "Generating doxygen documentation." VERBATIM)
+
+  IF(BUILD_DOCS)
+    ADD_CUSTOM_TARGET(doxygen ALL)
+  ENDIF()
+ENDIF()
+
+###################
+##### end: doxygen
+##################
+
+####################
+###### begin: crash reporter
+####################
+
+# if you haven't installed it, please visit
+# https://code.google.com/p/google-breakpad/ to get a copy of it
+# or run the script build_breakpad.sh under the scripts directory
+
+## set up our crash reporter: breakpad
+
+IF (PATH_TO_BREAKPAD_ROOT)
+    FIND_LIBRARY(BREAKPAD_LIBRARY breakpad
+      PATHS ${PATH_TO_BREAKPAD_ROOT}/out/Debug_Base
+      PATHS ${PATH_TO_BREAKPAD_ROOT}/out/Default/obj
+      NO_DEFAULT_PATH)
+    FIND_LIBRARY(BREAKPAD_UTILITIES_LIBRARY breakpad_utilities
+      PATHS ${PATH_TO_BREAKPAD_ROOT}/out/Debug_Base
+      PATHS ${PATH_TO_BREAKPAD_ROOT}/out/Default/obj
+      NO_DEFAULT_PATH)
+    MESSAGE(STATUS "Found library: ${BREAKPAD_LIBRARY}")
+    MESSAGE(STATUS "Found library: ${BREAKPAD_UTILITIES_LIBRARY}")
+
+    SET(seafile_client_sources ${seafile_client_sources} src/crash-handler.cpp)
+    INCLUDE_DIRECTORIES()
+    ADD_DEFINITIONS(-DSEAFILE_CLIENT_HAS_CRASH_REPORTER)
+    SET_SOURCE_FILES_PROPERTIES(src/crash-handler.cpp
+        PROPERTIES COMPILE_FLAGS "-I${PATH_TO_BREAKPAD_ROOT}/src")
+    SET(EXTRA_LIBS ${EXTRA_LIBS} ${BREAKPAD_LIBRARY} ${BREAKPAD_UTILITIES_LIBRARY})
+ENDIF()
+
+####################
+###### end: crash reporter
+####################
+
+####################
+###### start: freedesktop files
+####################
+
+if(NOT WIN32)
+install(DIRECTORY
+  ${CMAKE_SOURCE_DIR}/data/icons/16x16
+  ${CMAKE_SOURCE_DIR}/data/icons/22x22
+  ${CMAKE_SOURCE_DIR}/data/icons/24x24
+  ${CMAKE_SOURCE_DIR}/data/icons/32x32
+  ${CMAKE_SOURCE_DIR}/data/icons/48x48
+  ${CMAKE_SOURCE_DIR}/data/icons/128x128
+  ${CMAKE_SOURCE_DIR}/data/icons/scalable
+  DESTINATION share/icons/hicolor
+)
+
+install(FILES
+  ${CMAKE_SOURCE_DIR}/data/seafile.desktop
+  DESTINATION share/applications
+)
+
+install(FILES
+  ${CMAKE_SOURCE_DIR}/data/icons/128x128/apps/seafile.png
+  DESTINATION share/pixmaps
+)
+
+endif()
+
+####################
+###### end: freedesktop files
+####################
+
+ADD_EXECUTABLE(seafile-applet ${GUI_TYPE}
+  ${seafile_client_sources}
+  ${moc_output}
+  ${ui_output}
+  ${resources_ouput}
+  ${EXTRA_SOURCES}
+)
+
+INSTALL(TARGETS seafile-applet DESTINATION bin)
+
+TARGET_LINK_LIBRARIES(seafile-applet
+  ${SPARKLE_LIBS}
+  ${SC_LIBS}
+  ${QT_LIBRARIES}
+  ${OPENSSL_LIBRARIES}
+  ${LIBEVENT_LIBRARIES}
+  ${SQLITE3_LIBRARIES}
+  ${JANSSON_LIBRARIES}
+  ${LIBSEARPC_LIBRARIES}
+  ${LIBSEAFILE_LIBRARIES}
+  ${ZLIB_LIBRARIES}
+  ${EXTRA_LIBS}
+)
+
+target_link_libraries(seafile-applet Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network)
+IF (BUILD_SHIBBOLETH_SUPPORT)
+target_link_libraries(seafile-applet Qt5::${WEBKIT_NAME} Qt5::${WEBKIT_WIDGETS_NAME})
+ENDIF()
+
+## QtBus
+IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "BSD")
+  target_link_libraries(seafile-applet Qt5::DBus)
+ENDIF()
+
+### Xcode-related, build as a osx bundle
+IF(CMAKE_GENERATOR STREQUAL Xcode)
+  ADD_DEFINITIONS(-DXCODE_APP)
+  SET_TARGET_PROPERTIES(seafile-applet PROPERTIES
+    MACOSX_BUNDLE true
+    MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist
+  )
+  FIND_PROGRAM(seaf-daemon seaf-daemon)
+  SET(RESOURCES_DIR ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/seafile-applet.app/Contents/Resources)
+  ADD_CUSTOM_COMMAND(TARGET seafile-applet
+      POST_BUILD
+      COMMAND ${CMAKE_COMMAND} -E make_directory ${RESOURCES_DIR}
+      COMMAND ${CMAKE_COMMAND} -E copy seafile.icns ${RESOURCES_DIR}/.
+      COMMAND ${CMAKE_COMMAND} -E copy ${seaf-daemon} ${RESOURCES_DIR}/.
+  )
+  SET(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS "YES")
+  SET(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym")
+  SET(CMAKE_XCODE_ATTRIBUTE_GCC_ENABLE_PASCAL_STRINGS "NO")
+  SET(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES")
+ENDIF()
+
+SET(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${PROJECT_VERSION})
+ADD_CUSTOM_TARGET(dist
+    COMMAND ${git_executable} archive -v --prefix=${ARCHIVE_NAME}/ HEAD
+        | gzip > ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.gz
+    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+
+### Test related
+IF (BUILD_TESTING)
+    MACRO(ADD_QTEST testname)
+        QT5_WRAP_CPP(${testname}_MOCHEADER tests/${testname}.h)
+
+        SET(${testname}_SRCS tests/${testname}.cpp ${${testname}_MOCHEADER})
+
+        ADD_EXECUTABLE(${testname} ${${testname}_SRCS})
+
+        TARGET_LINK_LIBRARIES(${testname} ${QT_LIBRARIES}
+                ${QTESTLIB} ${SQLITE3_LIBRARIES} ${JANSSON_LIBRARIES}
+                ${EXTRA_LIBS} -lglib-2.0 ${SC_LIBS} ${ZLIB_LIBRARIES})
+        SET_TARGET_PROPERTIES(${testname} PROPERTIES
+          RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests )
+
+        INCLUDE_DIRECTORIES(${Qt5Test_INCLUDE_DIRS})
+
+        QT5_USE_MODULES(${testname} ${USE_QT_LIBRARIES} Test)
+
+        ADD_TEST(${testname} ${CMAKE_CURRENT_BINARY_DIR}/tests/${testname})
+
+    ENDMACRO(ADD_QTEST)
+
+    ENABLE_TESTING()
+    INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/tests)
+    ADD_QTEST(test_server-info)
+    ADD_QTEST(test_utils)
+    ADD_QTEST(test_file-utils)
+    ADD_QTEST(test_stl)
+ENDIF()
diff --git a/Doxyfile.in b/Doxyfile.in
new file mode 100644 (file)
index 0000000..328c439
--- /dev/null
@@ -0,0 +1,2351 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Seafile Client"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = @PACKAGE_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           = @CMAKE_CURRENT_SOURCE_DIR/seafile.ico
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = @CMAKE_CURRENT_BINARY_DIR@/docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = ../
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = @CMAKE_CURRENT_SOURCE_DIR@/src \
+                         @CMAKE_CURRENT_SOURCE_DIR@/README.md
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = .
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = com.seafile.seafile-applet
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           = third_party/QtAwesome
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH      =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/Info.plist b/Info.plist
new file mode 100644 (file)
index 0000000..2399b07
--- /dev/null
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleExecutable</key>
+       <string>seafile-applet</string>
+       <key>CFBundleGetInfoString</key>
+       <string>Seafile Client Application</string>
+       <key>CFBundleIconFile</key>
+       <string>seafile</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.seafile.seafile-client</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleName</key>
+       <string>Seafile</string>
+       <key>CFBundleShortVersionString</key>
+       <string>7.0.2</string>
+       <key>CFBundleVersion</key>
+       <string>7.0.2</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleURLTypes</key>
+       <array>
+               <dict>
+                       <key>CFBundleURLName</key>
+                       <string>com.seafile.seafile-client</string>
+                       <key>CFBundleURLSchemes</key>
+                       <array>
+                               <string>seafile</string>
+                       </array>
+               </dict>
+       </array>
+       <key>LSApplicationCategoryType</key>
+       <string>public.app-category.utilities</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>10.7</string>
+       <key>LSMinimumSystemVersionByArchitecture</key>
+       <dict>
+               <key>x86_64</key>
+               <string>10.7.0</string>
+       </dict>
+       <key>NSHumanReadableCopyright</key>
+       <string>Copyright © 2014 海文互知. All rights reserved.</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+       <key>NSHighResolutionCapable</key>
+       <string>True</string>
+       <key>NSSupportsAutomaticGraphicsSwitching</key>
+       <string>True</string>
+    <!-- For Sparkle Framework -->
+       <key>SUFeedURL</key>
+       <string>https://www.seafile.com/api/client-updates/seafile-client-mac/appcast.xml</string>
+       <key>CFBundleLocalizations</key>
+    <!-- The CFBundleLocalizations would determinte the display language used by sparkle AutoUpdate.app -->
+    <!-- We must list all languages supported by Sparkle here -->
+    <!-- Sparkle would choose one based on current system language -->
+    <!-- See https://github.com/sparkle-project/Sparkle/issues/238#issuecomment-11927292  -->
+    <array>
+      <string>ar</string>
+      <string>ca</string>
+      <string>cs</string>
+      <string>da</string>
+      <string>de</string>
+      <string>el</string>
+      <string>en</string>
+      <string>es</string>
+      <string>fi</string>
+      <string>fr</string>
+      <string>he</string>
+      <string>is</string>
+      <string>it</string>
+      <string>ja</string>
+      <string>ko</string>
+      <string>nb</string>
+      <string>nl</string>
+      <string>pl</string>
+      <string>pt_BR</string>
+      <string>pt_PT</string>
+      <string>ro</string>
+      <string>ru</string>
+      <string>sk</string>
+      <string>sl</string>
+      <string>sv</string>
+      <string>th</string>
+      <string>tr</string>
+      <string>uk</string>
+      <string>zh_CN</string>
+      <string>zh_TW</string>
+    </array>
+</dict>
+</plist>
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..fc82bff
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,215 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "[]" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+======================================================================
+For QtAwesome (third_party/QtAwesome):
+======================================================================
+
+All files in QtAwesome are
+Copyright 2013-2015 Reliable Bits Software by Blommers IT. All Rights Reserved. Author Rick Blommers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..7cd99d8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,48 @@
+## seafile-client [![Build Status](https://secure.travis-ci.org/haiwen/seafile-client.svg?branch=master)](http://travis-ci.org/haiwen/seafile-client)
+
+[Seafile](https://seafile.com) desktop client.
+
+## BUILD ##
+
+### Prerequisites ###
+
+- Qt5
+- cmake
+- [libsearpc](https://github.com/haiwen/libsearpc)
+- [seafile](https://github.com/haiwen/seafile)
+
+### INSTALL ###
+
+```
+cmake .
+make
+make install
+```
+
+> Qt 5.2 or higher is required
+
+Ubuntu users can install seafile client from this [PPA](https://code.launchpad.net/~seafile/+archive/ubuntu/seafile-client)
+
+### INSTALL with Qt5 ###
+
+```
+cmake .
+make
+make install
+```
+
+> Qt 5.5 or higher is recommanded but not required
+
+## Internationalization
+
+You are welcome to add translation in your language.
+
+### Contribute your translation
+
+Please submit translations via Transifex: https://www.transifex.com/projects/p/seafile-client/
+
+Steps:
+
+1. Create a free account on Transifex (https://www.transifex.com/).
+2. Send a request to join the language translation.
+3. After accepted by the project maintainer, then you can translate online.
diff --git a/coding-style.md b/coding-style.md
new file mode 100644 (file)
index 0000000..16f2ffb
--- /dev/null
@@ -0,0 +1,43 @@
+## C++ Coding Style
+
+Mainly borrowed from [google c++ style coding style](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml)
+
+### Naming Conventions
+
+#### Member Vairables
+
+Lower case words seprated by underscores, and ends with an underscore, e.g. `repos_list_`, `context_menu_`
+
+#### Variables in Qt Ui Files
+
+Camel case starts with a "m", e.g. `mUserNameText`, `mServerAddr`
+
+#### Functions
+
+Camel case, e.g. `showRepos`
+
+#### Setter and Getter
+
+- setter: `setRepoName()`
+- getter: `repoName()`
+
+#### Constants
+
+Camel case starts with "k", e.g. :
+
+    const int kRepoRefreshInterval = 1000;
+    const char *kDefaultName = "seafile";
+
+Use constants variables instead of macros to define constants.
+
+### Invoking functions
+
+- constant function parameter must be passed by object reference
+- No `this->` when invoking member functions.
+
+### Others
+
+- no source file scope static variable/function, use anonymous namespace
+- use forward declaration when possible, instead of including unnecessary header files
+- Never use exceptions
+
diff --git a/data/icons/128x128/apps/seafile.png b/data/icons/128x128/apps/seafile.png
new file mode 100644 (file)
index 0000000..cb394b2
Binary files /dev/null and b/data/icons/128x128/apps/seafile.png differ
diff --git a/data/icons/16x16/apps/seafile.png b/data/icons/16x16/apps/seafile.png
new file mode 100644 (file)
index 0000000..ba93533
Binary files /dev/null and b/data/icons/16x16/apps/seafile.png differ
diff --git a/data/icons/22x22/apps/seafile.png b/data/icons/22x22/apps/seafile.png
new file mode 100644 (file)
index 0000000..4639916
Binary files /dev/null and b/data/icons/22x22/apps/seafile.png differ
diff --git a/data/icons/24x24/apps/seafile.png b/data/icons/24x24/apps/seafile.png
new file mode 100644 (file)
index 0000000..73a7f1d
Binary files /dev/null and b/data/icons/24x24/apps/seafile.png differ
diff --git a/data/icons/32x32/apps/seafile.png b/data/icons/32x32/apps/seafile.png
new file mode 100644 (file)
index 0000000..f6442ea
Binary files /dev/null and b/data/icons/32x32/apps/seafile.png differ
diff --git a/data/icons/48x48/apps/seafile.png b/data/icons/48x48/apps/seafile.png
new file mode 100644 (file)
index 0000000..2c06762
Binary files /dev/null and b/data/icons/48x48/apps/seafile.png differ
diff --git a/data/icons/scalable/apps/seafile.svg b/data/icons/scalable/apps/seafile.svg
new file mode 100755 (executable)
index 0000000..d0d75d2
--- /dev/null
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="svg3828"
+   width="170.66667"
+   height="170.66667"
+   viewBox="0 0 170.66667 170.66667"
+   sodipodi:docname="seafile-new.svg"
+   inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
+  <metadata
+     id="metadata3834">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs3832" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="640"
+     inkscape:window-height="480"
+     id="namedview3830"
+     showgrid="false"
+     inkscape:zoom="1.3828125"
+     inkscape:cx="85.333336"
+     inkscape:cy="85.333336"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg3828" />
+  <image
+     width="170.66667"
+     height="170.66667"
+     preserveAspectRatio="none"
+     style="image-rendering:optimizeQuality"
+     xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA
+B3RJTUUH3gENCCIF8iHFhQAAIQpJREFUeNrtnXl8HMW1779V3T0arWNt1uJ9kbG8YwwECJsNgdhg
+lgAJPG7s3OB8/LiY9wLcm1x4yQNDcrm55MMn5kJICAQ/SFgcVmPCJsALEBYb27KRF3mRZUuyVku2
+pJGmu+v90SONxtJIM6MZSQb9Pp/62Orprjp1zulTp06dqoZhDGMYwxjGMIYxjGF84yAGm4BYQimF
+EIEuHTt2bKTb7T5NKTVJSjkGyAOygDQhRJJSSgcQQphKqRagCagFKm3bLhdC7PN6vbtHjBhRHaqN
+Ux2ndE+6CqO5uXm8lHKBlPLbwNlCiMIYt1UCfGrb9ibbtouSk5MPnkzDqYhTjvIOhn/++ef6zJkz
+bxBCXCuEuBJwDTAp7UqptUqpl4uLi18888wzzVNRGU4Jarsy1uv1LhVC3CKEOC/y3kpAQighKQXY
+oOxoaPxIKfUnt9v99Mk0D2UMaQo7mHj8+PHZLpfrZ0KIG8PqktRBAt56RPNhOHEA4W1AtB6F9jrw
+tYJt+gWOoxBSByMRXJmoxByUOx1SJqCSR4M7A2ycZ1Dh0P18e3v7g6mpqduGuiIMSco6mNbS0nK1
+pmm/7n08F6DpYLYgar9A1G9D1O1ANOwAZYE7ERKSUC4XQtdB00CTjjWQ/u7bynnrLRssC2WaiPZ2
+aGsBbysIDZU+A5U5A5UxG5U1D/QksHpXCKVUiWVZdyclJb06VBVhSFHURfDXa5q2SgiRG5JsXUcc
+24OoeB9RuQHRVAqpI1DJqYhEN8rtBl133nLV91vbczPCKaaJ8HpRrV5E83E4fgyVNhmVdwEqfz5q
+xBQwQyuDUqrKsqzbk5KS1gw1RRgSlHQx9ee7XK5nhBDjerxRGgjvUcTBl5Blb4B9AjUiE1JTIDGx
+f8IOm2N+pWhtheMnEMfqQKZgj7sCNf57KHcO2L5Q/Sxrb2//p9TU1I1DRREGnwLg8OHDGVlZWS9I
+KS/p8QbNQFStR+59FnFsByorFzwecLnAjtxhiymkhPZ2aGxE1FahRszALrgZlXshWD0rgm3b79XW
+1n5/9OjR9YNL/CAqQBdzf5eu6//V402agSx7BVnyJ9DbIWskKiXZEXqcX/SIIQApESeaobYaTBd2
+4S3Y464JqQimaf5rUlLSQ4NpDQZNAaqqqkamp6d/2KODpxnI8jeQOx6BRA2VnQ2GEX/zHisIAT4f
+oqYGWi3sGSuwx1zRoyIopUoaGhouys3NrY6ipX5DDmRj7733HgBNTU03ZWRkHO0mfGkgGkvQ370W
+WfooalweKj8/4MydKlAKdB2Vn48al4csfRT93WsRjSUgjaBbhRCFGRkZR5uamm4CKCoqGlBSB8wC
+dDH5f9V1vft8XploX65E1H6MGj0OXB1v/JBwU/rTc8citPsQh8tQWedinf5LEHq3Oy3Lei4xMfGm
+gRwSBsQCKKX44osvkr1e795uwpcGsvoj9LcXAvtQkwrA6PrGq1O84PTF0J2+sQ/97YXI6o+6WQNN
+0270er17N2/enKwGyOINiJpVVFSMz8zM3CmESApuXaJ9eS+i/mPU6LGhQ7RfNyiFOHwIlXEu1un3
+dgs9K6Va6uvrp+fl5R2MNylx53hNTc08j8fzebdmvUfRP1qO8iQ4U7oo4u+nNIR0po6NbZjnPQ7u
+HE6e2jQ2Np6ZnZ39RTzJiOsQUFNTc1E34QsdUfsJ+vqbUPnpkJb6zRM+OH1OS0Xlp6OvvwlR+0k3
+v8Dj8XxeU1NzUTzJiJsFqKmpWeDxeN4LuqgZyL2rkQeeRo2ewNCbzA8WBOLwAewJS7ELlnSbLjY2
+Nl6SnZ0dl+lBXBSgsrLynMzMzI+DLmoG2rYHEQ3rUTm5p9a0biAgBOJoFSr9QqzZP++mBHV1defm
+5eV9EvNmY1mZUory8vLTcnNzdwX9oBloX/wfaCuGjAxn9W0Y3SEF1NdDwkyseQ90U4KqqqqpY8aM
+2R3LKWLMfAClFBs2bMjIyckpDvpBM9C+uBvMnZCe7o/dD/bUbIgW23Z4ZO50eKYFTxNzcnKKN2zY
+kBHLKWJMVKkjcOH1eg9LKUcFCf/L+8G7BdI8DI/54UJAUyO452Kd/osgS2DbdoXb7R4Vq2BRTCyA
+EILm5ua3goQvdeSuP0LLZ5CW5l+qZbiEVZTDs5bPHB7KwOxASpnf3Nz8VqyGgZgoQF1d3R2GYVzW
+RSUQFe8iq14Cj3/MV8MlomIr8GQgq15CVLxLV2NtGMZldXV1d8RCdv1SI6UUu3btKpw0adJXQZU2
+H0L7dBkqb8w3c44fSwiJqCzHOvsJVPLYoJ9KS0unFRYWlvTHGvTbjrS2tlZpmpbTeUHZ6B9cg8rN
+cjT5GxLdjRsUzhSxqhbz4lf8mc0OLMs6mpiYmBt95f0cAhoaGh4JEr5moH12Byo7PfDmD/p4eooX
+AGWjstPRPrsjaGagaVpOQ0PDIwOuAEoptm/fPi05Ofm2wFWBPLAG5BFnPtvhzAyXGBQcnsojDo+7
+mNXk5OTbtm3bNi3aqWHUBrq5uXmvYRiTOy/4GtE/uhGVncNwlC9OEAJRcxTz3OfA5em87PP5SpOT
+kwuiqTIqC1BRUbHM5XIFhK8Z6JvvQWXm+D1+hks8iq1QmTnoW+4JGgpcLtfkioqKZdHIMioL4PV6
+vVLKhE4tqngfcfgxSEyOtsphhA0Frc2o0bdi58/vvGrbdpvb7XZHWlvEFqC6uvq+rsJHasi9/w2J
+KYM37tsW2O1gtTs5+bY1BMbtOPoDiSnI0v8GqQXEIGXC0aNH741UnpG+rlpbW5sZmHcK5N6nEM1F
+Tn78gEGA8oGWjEj/FqSchkjIAekCuw3lrYITu1ANn4Lt9a+zf838EttGJS/ALvjnzr4ppUhISNAB
+KwJOho+qqqr/m5GRcW/nBWWib7wa5ckYuI4rC9x5iLE/Qnjm9H37sS9QZX+G9tqgOfTXAaKxAfP8
+V4ISSerq6u7Ny8u7L+w6ImnQ6/W2SSmdffhCopX8HrybIq0myt4Cdrsj+NwrIn5cVbyEKv8LaAlf
+I2OgwH0eVuGtdMRdbNtud7vdCeHWEPYrcfDgwR9rmhY4hEFZUPNGgJB4F9tETn8wKuEDiPzvIQtX
++vftDbY7H6sC1KxzZOGHpmmugwcP/jhsvoR7Y1NT02632z2l4zG5/zlk49pIqogedjti+oOQelr/
+6zq2FbXrPsdf+FpAYXuuxJ54Ix1K4fV696SlpYXFrLAswNq1a2ckJiZO6byg68jKVxiYKZ8NY26K
+jfABRsyB/Ks7mXXqQziy0AN+QGJi4pR169bNCOfpsBRg3rx5K7qGGkXFRjDsgZn2aB7EqOtjy7Kx
+S0AkDIEpXYyKYTsy8UMpxdy5c1fETAE8Hs8PA0/oyKq3QXcR9zFOWYixPwyDwigw9n/4HafBHsdj
+UHSXI5MuiSNBMuuPAmzYsOEiwzACESarHdH4aSAoEdeiIPuCuMhf5FzmBI+GgPxiwSfR+KkTCPPD
+MAz3xo0bL+q3AkycOPEHXc2/rCwCd+qAdEyMOD0uwverACJ1xhAQXoyKO9WRjR9KKSZMmNDnoVp9
+KkBaWtpVgbsNRO0mf0Al3uZfoVJi5PiFgEqd0gcNNlhtYLWClgTuXKcYHrDbwPLiTMEGW/rKyRyq
+3RS04TQtLW1xXzzQe/txxYoVY5KSknLtjmNYBIjGLxwLEB+R0NmQshDukXFqxw93jl+AJ70HlhdS
+C2DkxYgRcyFpTM/Pt9fBsW1QuwlV96kTZBrExTDRGLyNMCkpKff2228fs2rVqvJQz/SqAMuWLVsY
+5P3XbAYjxpE02weuDMg8CxJHO9alrQYaNhP33euNu0B1EZjlhezzEeOXQjiZVq5MGDkfRs5HWG2o
+8ueh/KVu274HDEYConYzKmMW4AwDy5YtW7hq1ao/hHqkVwXIyMiYH1AAgTi21d+5GGiAAlwexGk/
+Bc+s7r9P+FFceaX2/A5qPgShOc6mkYaY8xAkT4iuQi0BMX4JjLketfMBaNwZtFo3IJAG4thWVMZs
+QKGUIj09fT4QnQIkJyefE6hcRzTt8Mu+vwqgYMQsxIyVA8ugjtbLX4CjRY7wbQsy5iGm/yI2lWtJ
+iFm/Rh1+CfY/BTIhBvwKF8KRkdQ7j6oLkmEP6E0B3MnJyYHBT4Jo+gpcSfQbSeMGTfg07YL9qx3B
+2BbkXYYo+JeYNyNGfw/c+Y41GLCws3JkJHGOtgX8MnQD3p6eCDnIPv3003NklzV+0XQINEG/vVW7
+DTHr/gFiSA8s2nGvXyA2ZJ8XF+F3IuscxNQ7nBnDQM0GNOHIyg8pJU8//fScUCSGtABTp06dHZRp
+2nLIWXfuV8KnQORcAkZabBjcXIZq3AHNh8DX6DBAT4WkUYi0aXDSeog68AyYrYAAdy6i8GexoaM3
+5Cxw/IGqATr9S+iOrJLynD4rxdSpU2cD/+jp9pAK4PF4pgbNAFrK/Q5TP4hTPsiZ348KAGWiDj4H
+R9aCr8l5m4UImkGiFEr5QLgg/3LEhJsdxSh73mGQ3YaY/at4sL9HiCm3o2o+BetE/N0BoSFaylGc
+7bBLKTwez9RQt4dUALfbPTFQqUR4K/tPvO2D1ClRP64Ovwalf3QUEeF3sAimS+H8JvzjbsXfUeWv
+woiZgQDWmGsgIav/zI4AYupPUdt/Gf8posKRlZB0JIkkJCRMCnV7bwowOkC9Bq1HozP/tgkjpjmC
+r17vHLMecads1Ja7oGl3wAop0wkWeaY5e+b0ZCdvoPUoqnEnmM0B50smQNMeQDj3TIzvFLNHZM6D
+xFHgPRr/tlqP+vnkKEBiYuKoULeGVADDMAJhOIET9YpYAWwYdz1ikp/hBT9x6ohkM6MyUZ/8GNrr
+Ha22fZA8FjHxh5B9Xid5XSEATuxHHVoDle+B5naURoDImT9ogRox7nrUrt8R9wBXe10QUwzDyAl1
+ayhKNMMwgjI9RVtt5ISYrQHhd1YUWahUfXortNU7ArQtxLS7EGf/oVP4IZEyETHtZ4hznwFXFqCc
+gxbyLu0ve6NH7qXO2kKccbKsDMNIB3qMSoVUAF3vYqsFDuHR5LD3A2r3Y9ByxG81DMR5/w9yF0RW
+SWIu4tw/Oz6A7YOMeK4w9gEhEGmFUfAxwmK1nWwBkghh7XtTgOArti9yQrQEVOlT0TGr5TCUveT/
+QyHOfbJfjps4/T8g/7vxEWwEUCOm07HaGb+NMsGHS2maBiFkHcoHkFJKguIAKuy9Bl2rgQPPoxqK
+wTMtAvMvoPZzZ+w22xBzfw2u9H4zX0y/q9919BtJY5zDoOK5R+EkWfkDepErgGV1qUjZ0c0ChA6N
+u50SDTLnQtZZ8WPWAEMkZKCURVyXjU86lSUaBcA++VMsHatmAwm7HVEQ1abXoQvRcQx+HHkpgv09
+u5fP6oSyQ8o0ze6EDzQSMiEtqm3vQxd22wBEA4Nl5Zdlj62GsgDK5/NZmt97QOFfPWtnQJH9rYFt
+72S0VEDjLpS3FrDBlY5ImwSpk6OuUnnr/KHrOGqBDE7a8fl8HXlr3RBKAaz29vYTbrfb03lFSx6Q
+OWyAUwpSJvW/nmiaLn0Gyl6GtgYnaNThsCkbpUzn2uhFiCn/DEaE6XEnykB15FTGCVpy0J/t7e0n
+CLFjONQQYHu93roAR0DFOz/vZCgbkdB/zz8iVH+CevtyKH0GzBYnx6+rty6kP7wsoPxN1LtXovY9
+F1kb9dsdL10p8DU7wakY64Jyjwyq0+v11tOZIRCMUBbAbG5urgWcBSFlQ+JIaCyJLaW9d4OBPGNQ
+lTwK+1/0J3YSnomWLtjzJ1T9l4gzf9P3/bYPGooRM++C8dc51xqK4ch7qENrgzZ29AuJI4N455el
+2dOtISejx48fPxLgjoVy58c/gtW1IP1jb/yhtv4aDrzsCDQKOqnZgvr83/tup3wd5F8aED5A+kyY
+8VPEd9+B3Av9EVf6xTtHVgGLf/z48cOhaOpRAbKysuzq6uoDXU+gVMmjnBSqgUTjnrg3obY9CEfe
+619gRgio/gccfLn3+46VIM4IkQ0ldMScexCz73ayk6OFbaGSAot/Qgiqq6sPZGVl9WhOe+x1bW0t
++/bt29U1JYyUif4lWAauHP0oekaEAbXtQTj8dpcl5j6KbYPpBd8Jp9hW4Deho3asCtqeFQTfCcTs
+vq0Eoy9DzP65U09UfDMhNZDKIaVk3759u2tre7amIdX+iSee2B5kAdImD/zhS94GOBrzj2Q4/dn6
+IJS/DWhhxNYtMEbA9NsQl6xBLP4EMfdeSDxpWBQ6au/qnhs0UsInbsxCyL0gynUAy5GVH0IInnji
+iW2hmuotHpnV1NR01O12O0qiGWgf3oxorYyLQIJgeRH5F8OE70HG7JjHzdW230D5m90iZj3T0g7T
+b0VM8m+zs32oD5dAS2XPdOlJiMvW9p9I04t685KAUxpu3xLzsC56tvMbA16v105LS8sBejQBvXG2
+uaKiIvDpF9tCpc+Mv9l3pSMWvADzHoDM0+Mj/EPrcN78Pmgx2xDnPBwQPqA+ug1ajjqs6+mZ1jqI
+hfOquxGjL4uYfyp9ZpCvVlFRsRtoDtVMb9xtP3To0JbOYUDZqMwznBSvuHj9ClJGIy79GySPJh5Q
+234DZW8QltlXFhQug+x5gQrqdzilt+ekDo17Y0PwqAWRLcPbpiMj/xRQCMGhQ4e2ACFDuL0pgLVp
+06YNXR1BNfJbfg811q89jhd84ZNxETyA2v5bR/hCC48mPQUxZUlwHdX/8AeCentWoNqOxYbojJl+
+pzJMPlpe1MizOx+XUrJp06b19HJuYK/2deXKlR/4fF2SC1wpqLSC2MvfthAz/lePH1SOBdS238L+
+VwnL7Cuct2nS97tXZLaG0RcbEU3ia08wUoNnGn2Z/9QCcAVC0z6fj5UrV37YWxN9DbBH9+3bFwj/
+WSYq7yI6cwNimcEyblEMRR6A2vZbOPBKYDk7zJQqkdN9S51IK+h7CLTbIOfsKCgN2YMw6bZR+ReB
+FQj4lZaWlgBVUStAampqy+bNm4sCw4BCjbo05sOASJ8eH+Fvfxj2vxy+2e8otgmpY7tXOPZy6Dwq
+scfXHybe4GQyxQJWm19EYZr/UZfSMaRKKfnyyy+LUlNTW3prolcFOH78uHXnnXe+FOQHpI1z8vBj
+OAQo14jYMKwL1LaHofRv/u1sUdAVYoooLng8sIDTtVg+yDwdMSeGaWcNJWHTr5LHotLGBQQrJXfc
+ccdLx48f7zV82+ccq6ampnj37t0HOy+YPtT4a/3DQBSM7aGI9sbYMQ2/8PetiV74SP9Urwd4ChBX
+vg3jroDEbGfenzkLcfavEN/+XUz7wZEPwuyD7cjEDPhru3fvPlhTU1PcVxN9el3JycnH1q9f/3pB
+QcHtHalF9oSrkcUPx8zUqfodMcuQU9tXQemL/TvIQhpQsxmS83v+3UhBnP6vMaK4l77sf6Xjf73f
+aLVhT7g6QL6UrF+//vXk5ORjzc3NvT7apwVobm62li9f/mxQiph0O+NNzBxBoPyd/jNs+yrY89fA
+LuaoYxICVfpinMQaZl+KHw3b2VajLgUZeBlN02T58uXPNjc397l6F26Ybfcnn3wSWJlRJvZpSxFW
+a2x6KzT48qH+1VH8CGLPX2O37evYHqj8uP/1RIP6r2DXasLJHBZWK/ZpS0EFXlC/rMJKww5LAVwu
+1/H777//CcMIMFeNKEBlzkEoFZOCrwXevyU6hhU/CruedYJJMaJHCAM++TnE2D/pE4374INlCOkK
+i06VOQc1IpA4axgG999//xMul+t4OM1FMvTmbd++fdPUqVM71xpFw1foH/wY9MgWLEJCAamj4cLH
+wJ3Z9/22Dz5/AMr+3u1L27GBcCJ/858AzwDkJ5a+CFse8k81w/BfzDbMi59EpU/rvLRr1679s2bN
++jYQ1qpd2MdYpaWltTY2NiZce+21l3TmmafkI6s/R7TWxI4J7U1Q8jR4a5xTLnpShJZK543f+L+h
+6UB4q3rRQlmw9zlorYa0iZDgiW39tg8OroOP/w3K34soLUxlzsSe/hM6Yv+GYXD33Xf/5759+95t
+a2sLywOO1PkeX1JSsmnSpEmdKSfiRDn6W9eBnhhbxqCcOLjUwTPBCYuardBU5iRj6O4oyO8nPaYX
+XGmQNt5vcfrRvrKguQpOHHH6EqkSm62Yl/8NlRI4x2vfvn1HCgsLvw0cDLeaiFpNSUk5UVlZqd1w
+ww0BK+DORDRXIJr295PBPUBqTrpVW6PzBrY1AHbskicjpkd3BOetg9Yah6aoS60TUdWMiLfMA9hj
+L8eeeE3Q23/bbbf9uqys7O329vaws2mjUeFxn3322btz5swJeB62ifHafH91Uc69hxEmHB77rno/
+6EXYunXr3rPOOutSoCyS2iLOtkhKSipfunTpg0H5glLHOuPfB37n0DcRts/hdRfhSylZunTpg0lJ
+SeWRVhexArS0tNhfffXVG2vWrCnqmjNoT1iMypwT0zWC4dK9qMzZ2BMCh4ALIVizZk3RV1999UZL
+S0vEGymi9WIEcEF1dfVbI0aM6BKCasV4/TKGh4H4wbf4Xb8D7ODYsWPekSNHXg5sIArGRz1/SkpK
+qtm1a5d24403XtDpEEoDMmYgD7wW36nZNxFWG9b5q4JW/AzDYMmSJQ+WlZW94AvK3AkfUUvJ5/P5
+SkpK9s+cOfOswsLCMR2niai0cQizFVFbzPCHpGMEZWOfdjN2wfWdXr+UkldeeeXj++677x6fzxd1
+Fmp/JSSAC8vKyl7Ny8sLREg0A/3dHyHqd8agiW86FCpjOualf+5M9QaorKxsHDdu3NXAevox5vZb
+Om632z169OhlO3bsWCVP+oC08cZiZ848jOjhzsR3xetBl2zbZsaMGbcfPnz4Ca/X2499ZP0YAjpg
+mqZZX19/oLKyMu2aa66Z1/U4EnviVWh7XvDnqQ87hpFBgObCt+iVoBVOwzBYvnz5H4qKih4xTbOp
+v63EylNr+fLLL3fn5ORMO+ussyZ2dQrt8Veg7X0RZw4zCHw8FSEAoeFb+FLQ2oOu6zz++ONFDzzw
+wD1AxHP+UE3Fkuwz3n777dULFiyY1tUSiJYq9HXXMZD7/U9pCIm56G+opMB3i6SUFBUVfXXZZZct
+ATYTo9cpph6alFKzbfvizZs3/3nWrFmjg84ZbK3GWHddt0MMh3ESpIFv0d+cQx78EEKwffv2I2ec
+ccZSKeUHth27ffoxd9F1XTdM01y0c+fOP06ZMiU7SAnamzDevMFZ3BlGdyR48C180Vlx9EMIwZ49
+e2qmT5/+E13X15mmGdM3KC5zNMMw3D6fb/HOnTsfnTJlStbJJ47q7yxBNOyJ72mZpxKUjUqfgvmd
+1UEBtC7Cv80wjNd9Pl+/PP6eEBcJ+Hw+r67rr0+fPv1fiouLK4Omh0LDXPgC9oQrwWwb9Nj6oBez
+DXvClZgLXwgSvpSS4uLiyunTp9+m63pchA9xjtJomua2LOvyoqKihy6++OJJQZnFmoE88Cbapn8f
+vPX9wYYysc77D+wJC4OCPJqm8eGHH+5bsGDBXZqmvWVZ/TkzpnfENWCvlDKllPtWr169c8yYMafN
+mzdvVOfsQNkoz2TsKTcgj2xAeOv4xkQNlYVKG4+5aA0qcwZdD3QyDIOnnnrqs+uuu+5OKeW7th3f
+Nfa4r9gopWyg7PXXX99aXV2duWjRosIgn0B3YxfeBEJHVnw88F/bHGhY7VhzVmBd8F/dvicopWTF
+ihUv/+IXv7gH+FgpZUbXSPgYyFdOAAWzZs1a9s4779yWmZnpDlIEIaG1Fn3jzxBHP/cfjfJ1iRwJ
+sNpQuWdifvs/ITErKCYihKCurs77ne9855Ht27f/Cdg7UJ0fcJtrGEa2z+e7at26df+2cOHCgm6r
+mLqBLN+I9o+VTtLkqe4f2CYk52J965fYY84P2r/n5wdvvvnm3kWLFv3GMIxX+7OyFw0GZdAVQriV
+UucsWbLkfz7yyCPfS0xMlEHWABxF2Psa2paHnXN3TjVFsE1IzMSa+1Psgqu6CR6cA5xWrFjx0urV
+q38vhPhEKRU3Zy8UBtPrEkKI8Uqpq1977bXlixcvntJjToNuIA+8hdz2OKK+JA7p5zGG2YrKKMSe
+vRx7wuU9Ct4wDNauXbt38eLFvxdCvKqUOsggjXeD7nYLIRKVUmeff/75Nz355JM3TJ482dPtWwUA
+uoGoLUF+9Sxy/+t0Hsg0FGCbIAT2xMXY025GZRX2KHhd1yktLW285ZZbXtywYcNfhRCfKqVitMEy
+Ogy6AnTQoWnaSMuyLrz11lv/6Ze//OWl2dnZCUGfrAncCUIiD76F3L8OUf6+owzaQH2h2w+rHYRA
+jZmPPXER9vjL/bt5u9OsaRo1NTVtK1eufPexxx57RtO09ZZlVTMEvNyhogAdkP5h4cI777zz+3fc
+cccF+fn5iSHT3aTufIqt4h/IIxsRVZ8harYDEjQ9Np+5EcIRquV8qVRlzUDln4M96nxU/rfoOJ6t
+JxiGQUVFRevDDz+88aGHHnpeCLHeb+6HzLLoUFOADujAeOC8JUuWLL799tvPnzt3brZpmqhQAhWi
+c0gQNTsQdTsR9bsRjfvh+CHEiUpnJVJIp9tCdOl+x7kAynmLpYFKyYPUsSjPRFTGaajM6ajsGc7t
+HQdF9UiGQNd1tmzZUrNq1aqNq1evfh34CGe7Vtzn9ZFiqCpABzQpZb5t22dMnjz5onvuuWf+VVdd
+VZienq6HlQQrpH97mb+nvnaEtwHajzv7/DqWpqXhpFq7UlHudDBcgVi9bYWVx2AYBg0NDeZrr71W
+8qtf/er90tLSD6WUm23brqCXc/oGG0NdAbrS6QGmAHOuuOKKC2+++eYzFixYMDErK8uwLKvXL2PF
+A1JKNE2jtrbWV1RUtP8vf/nLlrVr134IbAX2AI0MgTG+L5wqCtAVOpAJTAYKZ86cOfcHP/jB7PPO
+O2/cnDlzcj0ej6aUwrKs0MNFpEwSAk3TEELQ2Nhobd269ehHH3108Pnnn99WXFy8BSgBSoE6hqCZ
+77Vvg01AP6EBqUAeMA4Yn5eXV/Dd7363YM6cOaMKCgoyx44d68nNzU3JyMiIaM5YX19vVlVVnTh0
+6FDj3r1767Zu3Xrk73//+97Kysq9OON5Gc4hDMcZwia+L5zqCnAyNCAJSMOxEtn+f9OBtOTk5Izx
+48enZWVlJaWkpCQYhqED+Hw+88SJE221tbUtBw8ebGpubm7AMeENOG91jf/fJqCFU1jgJ+PrpgCh
+oOEkvxg4Q0jH3x2ZKra/WDgm3PT//2sj6GEMYxjDGMYwhjGMYQyjE/8fduTUzhArffwAAAAASUVO
+RK5CYII=
+"
+     id="image3836"
+     x="0"
+     y="0" />
+  <path
+     style="fill:#000000;stroke-width:1.33333337"
+     d=""
+     id="path3838"
+     inkscape:connector-curvature="0" />
+</svg>
diff --git a/data/seafile.desktop b/data/seafile.desktop
new file mode 100644 (file)
index 0000000..0a47bd9
--- /dev/null
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Name=Seafile
+Comment=Seafile desktop sync client
+TryExec=seafile-applet
+Exec=seafile-applet
+Icon=seafile
+Type=Application
+Categories=Network;FileTransfer;
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644 (file)
index 0000000..adf92c9
--- /dev/null
@@ -0,0 +1,6 @@
+Seafile
+-------
+
+For more information about Seafile, please visit http://seafile.com
+
+ -- plt <freeplant@gmail.com>  Fri, 30 March 2012 16:43:10 +0800
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..099d557
--- /dev/null
@@ -0,0 +1,183 @@
+seafile-gui (7.0.2) unstable; urgency=low
+
+  * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Wed, 7 Aug 2019 10:52:10 +0800
+seafile-gui (7.0.1) unstable; urgency=low
+
+  * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 9 Jul 2019 18:25:10 +0800
+seafile-gui (7.0.0) unstable; urgency=low
+
+  * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 28 May 2019 10:20:10 +0800
+seafile-gui (6.2.11) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Thur, 17 Jan 2019 15:53:10 +0800
+seafile-gui (6.2.10) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 15 Jan 2019 16:24:10 +0800
+seafile-gui (6.2.9) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Sat, 8 Dec 2018 11:17:10 +0800
+seafile-gui (6.2.8) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 4 Dec 2018 11:51:10 +0800
+seafile-gui (6.2.7) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 20 Nov 2018 15:56:10 +0800
+seafile-gui (6.2.5) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 11 Sep 2018 16:46:10 +0800
+seafile-gui (6.2.4) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Fri, 3 Aug 2018 13:21:10 +0800
+seafile-gui (6.2.3) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Fri, 27 Jul 2018 14:40:10 +0800
+seafile-gui (6.2.2) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Fri, 6 Jul 2018 17:04:10 +0800
+seafile-gui (6.2.1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Fri, 6 Jul 2018 17:04:10 +0800
+seafile-gui (6.2.0) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 26 June 2018 17:04:10 +0800
+seafile-gui (6.1.8) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 8 May 2018 17:04:10 +0800
+seafile-gui (6.1.7) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Thur, 29 Mar 2018 14:48:10 +0800
+seafile-gui (6.1.6) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 2 Mar 2018 12:20:10 +0800
+seafile-gui (6.1.5) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Fri, 2 Feb 2018 13:59:10 +0800
+seafile-gui (6.1.4) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 19 Dec 2017 17:01:10 +0800
+seafile-gui (6.1.3) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Fri, 3  Nov 2017 13:51:10 +0800
+seafile-gui (6.1.2) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Wed, 25 Oct 2017 13:51:10 +0800
+
+
+seafile-gui (6.1.1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 19 Sep 2017 18:16:10 +0800
+
+seafile-gui (6.1.0) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Wed, 2 Aug 2017 16:37:10 +0800
+seafile-gui (6.0.7) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 20 Jun 2017 16:37:10 +0800
+seafile-gui (6.0.6) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Fri, 28 Apr 2017 16:37:10 +0800
+
+seafile-gui (6.0.4) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Tue, 21 Feb 2017 16:17:30 +0800
+
+seafile-gui (6.0.3) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Fri, 10 Feb 2017 16:49:07 +0800
+
+seafile-gui (6.0.1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Mon, 12 Dec 2016 14:51:07 +0800
+
+seafile-gui (6.0.0) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Fri, 14 Oct 2016 13:49:07 +0800
+
+seafile-gui (5.1.4) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com>  Fri, 29 Jul 2016 14:06:38 +0800
+
+seafile-gui (5.1.3-1ubuntu1) UNRELEASED; urgency=medium
+
+  * new upstream release
+
+ -- m.eik michalke <meik.michalke@hhu.de>  Fri, 01 Jul 2016 00:04:38 +0200
+
+seafile-gui (5.1.2-5ubuntu2) unstable; urgency=medium
+
+  * fixed package dependencies
+
+ -- m.eik michalke <meik.michalke@hhu.de>  Sat, 18 Jun 2016 12:20:04 +0200
+
+seafile-gui (5.1.2-5ubuntu1) unstable; urgency=medium
+
+  * repackaging with cleaned up orig.tar.xz archives
+  * improved the debian/control file
+
+ -- m.eik michalke <meik.michalke@hhu.de>  Fri, 17 Jun 2016 19:22:13 +0200
+
+seafile-gui (5.1.2-4) unstable; urgency=medium
+
+  * adjusted build dependencies
+  * updated the debian/copyright notice so people know who's responisble for the packaging
+  * rewrote the rules file, much simpler now
+  * prep for release on github
+
+ -- m.eik michalke <meik.michalke@hhu.de>  Thu, 16 Jun 2016 01:06:50 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..be74efb
--- /dev/null
@@ -0,0 +1,50 @@
+Source: seafile-gui
+Section: net
+Priority: extra
+Maintainer: m.eik michalke <meik.michalke@hhu.de>
+Build-Depends:
+    debhelper (>= 7),
+    libssl-dev,
+    libcurl4-openssl-dev,
+    libsqlite3-dev,
+    intltool,
+    libglib2.0-dev,
+    libevent-dev,
+    uuid-dev,
+    qtbase5-dev,
+    libqt5webkit5-dev,
+    qttools5-dev,
+    libtool,
+    valac,
+    libjansson-dev,
+    cmake,
+    qtchooser,
+    qttools5-dev-tools,
+    libsearpc-dev (>= 3.1.0),
+    libseafile-dev
+Standards-Version: 3.9.5
+Homepage: http://seafile.com
+
+Package: seafile-gui
+Architecture: any
+Depends:
+    ${shlibs:Depends},
+    ${misc:Depends},
+    seafile-daemon (>= 5.1.2)
+Conflicts: seafile
+Description: Seafile desktop client.
+ Seafile is an open source cloud storage system with features
+ on privacy protection and teamwork. Collections of files are
+ called libraries, and each library can be synced separately.
+ A library can also be encrypted with a user chosen password.
+ Seafile also allows users to create groups and easily sharing
+ files into groups.
+
+Package: seafile-gui-dbg
+Section: debug
+Architecture: any
+Depends:
+    seafile-gui (= ${binary:Version}),
+    ${misc:Depends},
+Description: Debugging symbols for the seafile-gui package.
+ This package contains the debugging symbols for the seafile-gui package.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..4cabdc0
--- /dev/null
@@ -0,0 +1,28 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: seafile-client
+Upstream-Contact: Lingtao Pan <freeplant@gmail.com>
+Source: https://github.com/haiwen/seafile-client
+
+Files: *
+Copyright: 2012 plt
+License: Apache
+  You should have received a copy of the license with your Debian system,
+  in the file /usr/share/common-licenses/Apache-2.0, or with the
+  source package as the file COPYING or LICENSE.
+
+Files: debian/*
+Copyright: 2016 m.eik michalke
+License: GPL-2
+  This program is free software; you can redistribute it
+  and/or modify it under the terms of the GNU General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later
+  version.
+  .
+  This software is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE.
+  .
+  You should have received a copy of the license with your Debian system,
+  in the file /usr/share/common-licenses/GPL-2, or with the
+  source package as the file COPYING or LICENSE.
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..97753b0
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+%:
+       dh $@ --builddirectory=build
+
+override_dh_auto_configure:
+       export QT_SELECT=5
+       dh_auto_configure -- -DCMAKE_BUILD_TYPE=Release -DBUILD_SHIBBOLETH_SUPPORT=ON
+
+override_dh_auto_build:
+       dh_auto_build --parallel
+
+override_dh_strip:
+       dh_strip -pseafile-gui --dbg-package=seafile-gui-dbg
diff --git a/debian/seafile-gui.install b/debian/seafile-gui.install
new file mode 100644 (file)
index 0000000..29143cc
--- /dev/null
@@ -0,0 +1,4 @@
+usr/bin/seafile-applet
+usr/share/pixmaps/seafile.png
+usr/share/applications/seafile.desktop
+usr/share/icons/hicolor/*/apps/seafile.png
diff --git a/debian/source/format b/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/dev-guide.md b/dev-guide.md
new file mode 100644 (file)
index 0000000..2498794
--- /dev/null
@@ -0,0 +1,33 @@
+## C++ Coding Style
+
+Refer to `coding-style.md`
+
+## I18N
+
+### update the .ts files
+
+        make update-ts
+
+
+### Add a new language
+
+1. add the language to the LANGUAGES variable in `CMakeLists.txt`
+
+        SET(LANGUAGES zh_CN xx_YY)
+
+2. make update-ts
+
+3. add a line to `seafile-client.qrc`
+
+        <file>i18n/seafile_xx_YY.qm</file>
+
+### Add a New Language Contributed by Others
+
+1. add the language to the LANGUAGES variable in `CMakeLists.txt`
+
+        SET(LANGUAGES zh_CN xx_YY)
+
+2. add a line to `seafile-client.qrc`
+
+        <file>i18n/seafile_xx_YY.qm</file>
+
diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt
new file mode 100644 (file)
index 0000000..25fc432
--- /dev/null
@@ -0,0 +1,53 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(seafile_shell_ext)
+
+OPTION(X32 "Build 32 bit instead of 64bit dll" OFF)
+
+IF (X32)
+  SET(WINVER 0x0501)
+  SET(DLL_NAME seafile_shell_ext)
+  set(CMAKE_RC_COMPILER windres)
+ELSE(X32)
+  SET(WINVER 0x0502)
+  SET(DLL_NAME seafile_shell_ext64)
+  set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
+ENDIF()
+
+IF (NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
+  SET(CMAKE_BUILD_TYPE Debug)
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g")
+ENDIF()
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fno-omit-frame-pointer -Wall -Wextra -Wno-unused-parameter -std=c++0x")
+
+ADD_DEFINITIONS(-D_WIN32_WINNT=${WINVER} -DWINVER=${WINVER})
+
+SET(CMAKE_CXX_CREATE_SHARED_LIBRARY
+    "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
+
+SET(ext_sources
+  dll.cpp
+  shell-ext.cpp
+  class-factory.cpp
+  context-menu.cpp
+  icon-overlay.cpp
+  log.cpp
+  applet-connection.cpp
+  commands.cpp
+  ext-utils.cpp
+  i18n.cpp
+  seafile_shell_ext.def
+  seafile_shell_ext.rc
+)
+
+SET_SOURCE_FILES_PROPERTIES(context-menu.cpp PROPERTIES COMPILE_FLAGS -fpermissive)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+LINK_LIBRARIES(uuid oleaut32 ole32 ws2_32 shlwapi userenv)
+
+ADD_LIBRARY(seafile_shell_ext SHARED ${ext_sources})
+SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
+
+SET_TARGET_PROPERTIES(seafile_shell_ext PROPERTIES
+  LINK_FLAGS "-static -lstdc++ -Wl,--enable-stdcall-fixup"
+  OUTPUT_NAME "${DLL_NAME}"
+  PREFIX "")
diff --git a/extensions/README.md b/extensions/README.md
new file mode 100644 (file)
index 0000000..1a37085
--- /dev/null
@@ -0,0 +1,34 @@
+This folder contains the code for Seafile Shell extension.
+
+
+## Build 64 bit DLL
+
+Download [MinGW64 toochain](http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Automated%20Builds/mingw-w64-bin_i686-mingw_20111220.zip/download)
+
+Or download the [online-installer](http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe/download)
+
+## String Encoding
+
+There are three encoding involved in the extension:
+
+- windows unicode (`wchar_t *`)
+- utf8
+- windows multi bytes encoding (ANSI)
+
+The conventions are:
+
+- Strings in internal data structures must be stored as utf8.
+- Messages exchanged between shell extension and seafile applet should be encoded in utf8.
+
+
+## Debugging tips
+
+When developing the shell extensions, one need to restart the explorer frequently to reload the extension. Here is a piece of code that can programmatically stop explorer: (From http://stackoverflow.com/a/5705965/1467959)
+
+```c
+BOOL ExitExplorer()
+{
+    HWND hWndTray = FindWindow(_T("Shell_TrayWnd"), NULL);
+    return PostMessage(hWndTray, 0x5B4, 0, 0);
+}
+```
diff --git a/extensions/README.org b/extensions/README.org
new file mode 100644 (file)
index 0000000..eae77ee
--- /dev/null
@@ -0,0 +1,88 @@
+#+ -*- mode: org; fill-column: 70; -*-
+#+title: Shell Extension for Seafile using COM
+#+startup: showall
+
+
+* Useful Links
+
+  Introduction to COM - What It Is and How to Use It.
+
+  http://www.codeproject.com/KB/COM/comintro.aspx
+
+  Creating shell extension handlers
+
+  http://msdn.microsoft.com/en-us/library/bb776797.aspx
+
+  Creating context menu handlers
+
+  http://msdn.microsoft.com/en-us/library/bb776881.aspx
+  
+
+* What is Shell
+
+  Windows Shell is just the Windows Explorer, i.e. *explorer.exe*.
+
+* What is COM
+
+  + COM is short for "Component Object Model"
+  + COM is always in the form of a DLL with several specific rules.
+  + A DLL is called a *COM Server*, while the one using the dll is
+    called a *COM client*.
+  
+  In shell extension, we are writing a COM Server, and the Windows
+  Shell is our client. For example, for a menu handler, which is used
+  to add a customized menu item, the Winodws Explorer calls some
+  function in our COM with a param descrbing the current file for whom
+  the menu is being displayed. In our COM implementation, we decide
+  what menu items to add by analysing this param, and use shell API
+  like =InsertMenuItem= to add menu items.
+  
+* How to implement a COM
+  
+  COM can be implented in any programming language which has a concept
+  of *function pointer*. In practice, people mainly use C++.  
+
+* How do Shell know which function in the interface to call
+
+  Our menu items are to be added in two steps:
+
+  1) Shell queries you where is the handler function, and you give a
+     pointer to it;
+  2) Shell calls this function using that pointer and corresponding
+     args.
+
+
+  To be concrete, you provide a =QueryInterface()= function, and
+  accept a GUID as one of the params. In the implementation of this
+  function, if the guid param is =IID_IContextMenu=, you just return
+  the func pointer to the context menu hanlder, and the shell will use
+  that pointer to call your menu hanlder, which is your main routine
+  to add your customized menu items, later on.
+
+  
+* Control flow of the display a customized menu
+  
+  1) users right click
+
+  2) shell finds the registration info in system registry and gets to
+     know we are intereseted to add customized menu items
+  
+  3) shell loads the dll, and calls Dll's GetClassObject function,
+     which return a pointer to dll's *factory class*.
+  
+  4) shell calls factory's CreateInstance method to create a object of
+     the extension, i.e. seaf_shell_ext.
+
+  5) shell calls seaf_shell_ext->vtable->initialize with args to tell
+     the extension about the calling enviroment: whether the click is
+     a background click, or a click on a file; and supply the file
+     object or a folder object as well.
+     
+  6) shell asks the extension object for the IContextMenu Interface,
+     i.e. calls its QueryInterface method with IID_IContextMenu as a
+     param. The object returns a pointer to the seaf_menu structure.
+  
+  7) shell calls the seaf_menu->vtable->QueryContextMenu, and we
+     decide *what to add to the menu.*
+     
+
diff --git a/extensions/applet-connection.cpp b/extensions/applet-connection.cpp
new file mode 100644 (file)
index 0000000..ed0cd26
--- /dev/null
@@ -0,0 +1,214 @@
+#define __STDC_LIMIT_MACROS
+#include "ext-common.h"
+
+#include <memory>
+
+#include "ext-utils.h"
+#include "log.h"
+
+#include "applet-connection.h"
+
+namespace {
+
+const char *kSeafExtPipeName = "\\\\.\\pipe\\seafile_ext_pipe";
+
+struct ThreadData {
+    seafile::AppletConnection *conn;
+    std::string cmd;
+};
+
+DWORD WINAPI sendDataWrapper (void *vdata)
+{
+    ThreadData *tdata = (ThreadData *)vdata;
+    bool ret = tdata->conn->sendCommandAndWait(tdata->cmd, NULL);
+    delete tdata;
+    ExitThread(ret);
+    return 0;
+}
+
+} // namespace
+
+namespace seafile {
+
+AppletConnection::AppletConnection()
+    : connected_(false),
+      pipe_(INVALID_HANDLE_VALUE),
+      last_conn_failure_(0)
+{
+}
+
+AppletConnection *AppletConnection::singleton_;
+
+AppletConnection *AppletConnection::instance()
+{
+    if (!singleton_) {
+        static AppletConnection v;
+        singleton_ = &v;
+    }
+    return singleton_;
+}
+
+
+bool
+AppletConnection::connect ()
+{
+    if (pipe_ != INVALID_HANDLE_VALUE) {
+        CloseHandle (pipe_);
+    }
+    pipe_ = CreateFile(
+        kSeafExtPipeName,       // pipe name
+        GENERIC_READ |          // read and write access
+        GENERIC_WRITE,
+        0,                      // no sharing
+        NULL,                   // default security attributes
+        OPEN_EXISTING,          // opens existing pipe
+        FILE_FLAG_OVERLAPPED,   // default attributes
+        NULL);                  // no template file
+
+    if (pipe_ == INVALID_HANDLE_VALUE) {
+        if (GetLastError() != ERROR_FILE_NOT_FOUND) {
+            seaf_ext_log("Failed to create named pipe: %s", utils::formatErrorMessage().c_str());
+        }
+        connected_ = false;
+        last_conn_failure_ = utils::currentMSecsSinceEpoch();
+        return false;
+    }
+
+    DWORD mode = PIPE_READMODE_MESSAGE;
+    if (!SetNamedPipeHandleState(pipe_, &mode, NULL, NULL)) {
+        seaf_ext_log("Failed to set named pipe mode: %s", utils::formatErrorMessage().c_str());
+        onPipeError();
+        last_conn_failure_ = utils::currentMSecsSinceEpoch();
+        return false;
+    }
+
+    connected_ = true;
+    return true;
+}
+
+bool
+AppletConnection::prepare()
+{
+    // HANDLE h_ev = CreateEvent
+    //     (NULL,                  /* security attribute */
+    //      FALSE,                 /* manual reset */
+    //      FALSE,                 /* initial state  */
+    //      NULL);                 /* event name */
+
+    // if (!h_ev) {
+    //     return false;
+    // }
+    return true;
+}
+
+
+bool AppletConnection::sendCommand(const std::string& cmd)
+{
+    ThreadData *tdata = new ThreadData;
+    tdata->conn = this;
+    tdata->cmd = cmd;
+    utils::doInThread((LPTHREAD_START_ROUTINE)sendDataWrapper, (void *)tdata);
+    return true;
+}
+
+bool AppletConnection::sendCommandAndWait(const std::string& cmd, std::string *resp)
+{
+    utils::MutexLocker lock(&mutex_);
+    if (!sendWithReconnect(cmd)) {
+        return false;
+    }
+
+    std::string r;
+    if (!readResponse(&r)) {
+        return false;
+    }
+
+    if (resp != NULL) {
+        *resp = r;
+    }
+
+    return true;
+}
+
+void AppletConnection::onPipeError()
+{
+    CloseHandle(pipe_);
+    pipe_ = INVALID_HANDLE_VALUE;
+    connected_ = false;
+}
+
+bool AppletConnection::writeRequest(const std::string& cmd)
+{
+    uint32_t len = cmd.size();
+    if (!utils::pipeWriteN(pipe_, &len, sizeof(len))) {
+        onPipeError();
+        seaf_ext_log("failed to send command: %s", utils::formatErrorMessage().c_str());
+        return false;
+    }
+
+    if (!utils::pipeWriteN(pipe_, cmd.c_str(), len)) {
+        onPipeError();
+        seaf_ext_log("failed to send command: %s", utils::formatErrorMessage().c_str());
+        return false;
+    }
+    return true;
+}
+
+bool AppletConnection::readResponse(std::string *out)
+{
+    uint32_t len = 0;
+    if (!utils::pipeReadN(pipe_, &len, sizeof(len))) {
+        onPipeError();
+        return false;
+    }
+
+    // avoid integer overflow
+    if (len == UINT32_MAX) {
+        return false;
+    }
+
+    if (len == 0) {
+        return true;
+    }
+
+    std::unique_ptr<char[]> buf(new char[len + 1]);
+    buf.get()[len] = 0;
+    if (!utils::pipeReadN(pipe_, buf.get(), len)) {
+        onPipeError();
+        return false;
+    }
+
+    if (out != NULL) {
+        *out = buf.get();
+    }
+
+    return true;
+}
+
+bool AppletConnection::sendWithReconnect(const std::string& cmd)
+{
+    uint64_t now = utils::currentMSecsSinceEpoch();
+    if (!connected_ && now - last_conn_failure_ < 2000) {
+        return false;
+    }
+    if (!connected_) {
+        if (connect() && writeRequest(cmd)) {
+            return true;
+        }
+    } else {
+        if (writeRequest(cmd)) {
+            return true;
+        } else if (!connected_ && connect()) {
+            // Retry one more time when connection is broken. This normally
+            // happens when seafile client was restarted.
+            seaf_ext_log ("reconnected to seafile cient");
+            if (writeRequest(cmd)) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+} // namespace seafile
diff --git a/extensions/applet-connection.h b/extensions/applet-connection.h
new file mode 100644 (file)
index 0000000..e12a167
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef SEAFILE_EXTENSION_APPLET_CONNECTION_H
+#define SEAFILE_EXTENSION_APPLET_CONNECTION_H
+
+#include <string>
+#include "ext-utils.h"
+
+namespace seafile {
+
+/**
+ * Connection to the seafile appplet, thourgh which the shell extension would
+ * execute an `AppletCommand`.
+ *
+ * It connects to seafile appelt through a named pipe.
+ */
+class AppletConnection {
+public:
+    static AppletConnection *instance();
+
+    bool prepare();
+    bool connect();
+
+    /**
+     * Send the command in a separate thread, returns immediately
+     */
+    bool sendCommand(const std::string& data);
+
+    /**
+     * Send the command and blocking wait for response.
+     */
+    bool sendCommandAndWait(const std::string& data, std::string *resp);
+
+private:
+    AppletConnection();
+    bool readResponse(std::string *out);
+    bool writeRequest(const std::string& cmd);
+    void onPipeError();
+
+    /**
+     * When sending request to seafile client, we would retry one
+     * more time if we're sure the connection to seafile client is broken.
+     * This normally happens when seafile client was restarted.
+     */
+    bool sendWithReconnect(const std::string& cmd);
+
+    static AppletConnection *singleton_;
+
+    bool connected_;
+    HANDLE pipe_;
+
+    uint64_t last_conn_failure_;
+
+    /**
+     * We have only one connection for each explorer process, so when sending
+     * a command to seafile client we need to ensure exclusive access.
+     */
+    utils::Mutex mutex_;
+};
+
+} // namespace seafile
+
+#endif // SEAFILE_EXTENSION_APPLET_CONNECTION_H
diff --git a/extensions/build.sh b/extensions/build.sh
new file mode 100644 (file)
index 0000000..513808d
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -e
+
+unset -v CPPFLAGS CFLAGS CXXFLAGS LDFLAGS
+
+SCRIPT=$(readlink -f "$0")
+SRCDIR=$(dirname "${SCRIPT}")
+
+cd $SRCDIR
+
+rm -rf CMakeCache.txt CMakeFiles
+export CXX=g++
+cmake -DX32=ON -G "MSYS Makefiles" .
+make
+
+rm -rf CMakeCache.txt CMakeFiles
+export CXX=x86_64-w64-mingw32-g++
+cmake -G "MSYS Makefiles" .
+make
diff --git a/extensions/class-factory.cpp b/extensions/class-factory.cpp
new file mode 100644 (file)
index 0000000..dbc5fa1
--- /dev/null
@@ -0,0 +1,87 @@
+
+#include "ext-common.h"
+
+#include "class-factory.h"
+#include "shell-ext.h"
+#include "log.h"
+
+ShellExtClassFactory::ShellExtClassFactory(seafile::RepoInfo::Status status)
+{
+    m_cRef = 0L;
+    status_ = status;
+
+    // seaf_ext_log ("new ShellExtClassFactory created for status %d\n", int(status));
+
+    InterlockedIncrement(&g_cRefThisDll);
+}
+
+ShellExtClassFactory::~ShellExtClassFactory()
+{
+    InterlockedDecrement(&g_cRefThisDll);
+}
+
+STDMETHODIMP ShellExtClassFactory::QueryInterface(REFIID riid,
+                                                   LPVOID FAR *ppv)
+{
+    if (ppv == 0)
+        return E_POINTER;
+
+    *ppv = NULL;
+
+    // Any interface on this object is the object pointer
+
+    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
+    {
+        *ppv = static_cast<LPCLASSFACTORY>(this);
+        AddRef();
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) ShellExtClassFactory::AddRef()
+{
+    return ++m_cRef;
+}
+
+STDMETHODIMP_(ULONG) ShellExtClassFactory::Release()
+{
+    if (--m_cRef)
+        return m_cRef;
+
+    delete this;
+
+    return 0L;
+}
+
+STDMETHODIMP ShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
+                                                   REFIID riid,
+                                                   LPVOID *ppvObj)
+{
+    if(ppvObj == 0)
+        return E_POINTER;
+
+    *ppvObj = NULL;
+
+    // Shell extensions typically don't support aggregation (inheritance)
+
+    if (pUnkOuter)
+        return CLASS_E_NOAGGREGATION;
+
+    // Create the main shell extension object.  The shell will then call
+    // QueryInterface with IID_IShellExtInit--this is how shell extensions are
+    // initialized.
+
+    ShellExt* pShellExt = new ShellExt(status_); // Create the ShellExt object
+
+    const HRESULT hr = pShellExt->QueryInterface(riid, ppvObj);
+    if(FAILED(hr))
+        delete pShellExt;
+    return hr;
+}
+
+STDMETHODIMP ShellExtClassFactory::LockServer(BOOL /*fLock*/)
+{
+    return E_NOTIMPL;
+}
diff --git a/extensions/class-factory.h b/extensions/class-factory.h
new file mode 100644 (file)
index 0000000..2793d2b
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef SEAFILE_EXT_SHELL_EXT_CLASS_FACTORY_H
+#define SEAFILE_EXT_SHELL_EXT_CLASS_FACTORY_H
+
+#include "shell-ext.h"
+
+/**
+ * Class factory's main responsibility is implemented in its `CreateInstance`
+ * member function, which creates instances of the required shell extension
+ * interface, such as IContextMenu.
+ *
+ * Class factory object is created by `DllGetClassObject` method for this
+ * extension.
+ */
+class ShellExtClassFactory : public IClassFactory
+{
+protected:
+    ULONG m_cRef;
+
+    seafile::RepoInfo::Status status_;
+
+public:
+    ShellExtClassFactory(seafile::RepoInfo::Status status = seafile::RepoInfo::NoStatus);
+    virtual ~ShellExtClassFactory();
+
+    //@{
+    /// IUnknown members
+    STDMETHODIMP         QueryInterface(REFIID, LPVOID FAR *);
+    STDMETHODIMP_(ULONG) AddRef();
+    STDMETHODIMP_(ULONG) Release();
+    //@}
+
+    //@{
+    /// IClassFactory members
+    STDMETHODIMP      CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *);
+    STDMETHODIMP      LockServer(BOOL);
+    //@}
+};
+
+#endif // SEAFILE_EXT_SHELL_EXT_CLASS_FACTORY_H
diff --git a/extensions/commands.cpp b/extensions/commands.cpp
new file mode 100644 (file)
index 0000000..6395767
--- /dev/null
@@ -0,0 +1,218 @@
+#include "ext-common.h"
+
+#include "log.h"
+#include "applet-connection.h"
+#include "ext-utils.h"
+
+#include "commands.h"
+
+namespace seafile {
+
+uint64_t reposInfoTimestamp = 0;
+
+std::string toString(RepoInfo::Status st) {
+    switch (st) {
+    case RepoInfo::NoStatus:
+        return "nostatus";
+    case RepoInfo::Paused:
+        return "paused";
+    case RepoInfo::Normal:
+        return "synced";
+    case RepoInfo::Syncing:
+        return "syncing";
+    case RepoInfo::Error:
+        return "error";
+    case RepoInfo::ReadOnly:
+        return "readonly";
+    case RepoInfo::LockedByMe:
+        return "locked by me";
+    case RepoInfo::LockedByOthers:
+        return "locked by someone else";
+    case RepoInfo::N_Status:
+        return "";
+    }
+    return "";
+}
+
+
+GetShareLinkCommand::GetShareLinkCommand(const std::string path)
+    : AppletCommand<void>("get-share-link"),
+      path_(path)
+{
+}
+
+std::string GetShareLinkCommand::serialize()
+{
+    return path_;
+}
+
+GetInternalLinkCommand::GetInternalLinkCommand(const std::string path)
+    : AppletCommand<void>("get-internal-link"),
+      path_(path)
+{
+}
+
+std::string GetInternalLinkCommand::serialize()
+{
+    return path_;
+}
+
+ListReposCommand::ListReposCommand()
+    : AppletCommand<RepoInfoList>("list-repos")
+{
+}
+
+std::string ListReposCommand::serialize()
+{
+    char buf[512];
+    snprintf (buf, sizeof(buf), "%I64u", reposInfoTimestamp);
+    return buf;
+}
+
+bool ListReposCommand::parseResponse(const std::string& raw_resp,
+                                     RepoInfoList* infos)
+{
+    std::vector<std::string> lines = utils::split(raw_resp, '\n');
+    if (lines.empty()) {
+        return true;
+    }
+    for (size_t i = 0; i < lines.size(); i++) {
+        std::string line = lines[i];
+        std::vector<std::string> parts = utils::split(line, '\t');
+        if (parts.size() != 6) {
+            continue;
+        }
+        std::string repo_id, repo_name, worktree, status;
+        RepoInfo::Status st;
+        bool support_file_lock;
+        bool support_private_share;
+
+        repo_id = parts[0];
+        repo_name = parts[1];
+        worktree = utils::normalizedPath(parts[2]);
+        status = parts[3];
+        support_file_lock = parts[4] == "file-lock-supported";
+        support_private_share = parts[5] == "private-share-supported";
+        if (status == "paused") {
+            st = RepoInfo::Paused;
+        }
+        else if (status == "syncing") {
+            st = RepoInfo::Syncing;
+        }
+        else if (status == "error") {
+            st = RepoInfo::Error;
+        }
+        else if (status == "normal") {
+            st = RepoInfo::Normal;
+        }
+        else {
+            // impossible
+            seaf_ext_log("bad repo status \"%s\"", status.c_str());
+            continue;
+        }
+        // seaf_ext_log ("status for %s is \"%s\"", repo_name.c_str(),
+        // status.c_str());
+        infos->push_back(RepoInfo(repo_id, repo_name, worktree, st,
+                                  support_file_lock, support_private_share));
+    }
+
+    reposInfoTimestamp = utils::currentMSecsSinceEpoch();
+    return true;
+}
+
+GetFileStatusCommand::GetFileStatusCommand(const std::string& repo_id,
+                                           const std::string& path_in_repo,
+                                           bool isdir)
+    : AppletCommand<RepoInfo::Status>("get-file-status"),
+    repo_id_(repo_id),
+    path_in_repo_(path_in_repo),
+    isdir_(isdir)
+{
+}
+
+std::string GetFileStatusCommand::serialize()
+{
+    char buf[512];
+    snprintf (buf, sizeof(buf), "%s\t%s\t%s",
+              repo_id_.c_str(), path_in_repo_.c_str(), isdir_ ? "true" : "false");
+    return buf;
+}
+
+bool GetFileStatusCommand::parseResponse(const std::string& raw_resp,
+                                         RepoInfo::Status *status)
+{
+    // seaf_ext_log ("raw_resp is %s\n", raw_resp.c_str());
+
+    if (raw_resp == "syncing") {
+        *status = RepoInfo::Syncing;
+    } else if (raw_resp == "synced") {
+        *status = RepoInfo::Normal;
+    } else if (raw_resp == "error") {
+        *status = RepoInfo::Error;
+    } else if (raw_resp == "paused") {
+        *status = RepoInfo::Paused;
+    } else if (raw_resp == "readonly") {
+        *status = RepoInfo::ReadOnly;
+    } else if (raw_resp == "locked") {
+        *status = RepoInfo::LockedByOthers;
+    } else if (raw_resp == "locked_by_me") {
+        *status = RepoInfo::LockedByMe;
+    } else if (raw_resp == "ignored") {
+        *status = RepoInfo::NoStatus;
+    } else {
+        *status = RepoInfo::NoStatus;
+
+        // seaf_ext_log ("[GetFileStatusCommand] status for %s is %s, raw_resp is %s\n",
+        //               path_in_repo_.c_str(),
+        //               seafile::toString(*status).c_str(), raw_resp.c_str());
+    }
+
+    return true;
+}
+
+LockFileCommand::LockFileCommand(const std::string& path)
+    : AppletCommand<void>("lock-file"),
+    path_(path)
+{
+}
+
+std::string LockFileCommand::serialize()
+{
+    return path_;
+}
+
+UnlockFileCommand::UnlockFileCommand(const std::string& path)
+    : AppletCommand<void>("unlock-file"),
+    path_(path)
+{
+}
+
+std::string UnlockFileCommand::serialize()
+{
+    return path_;
+}
+
+PrivateShareCommand::PrivateShareCommand(const std::string& path, bool to_group)
+    : AppletCommand<void>(to_group ? "private-share-to-group"
+                                   : "private-share-to-user"),
+      path_(path)
+{
+}
+
+std::string PrivateShareCommand::serialize()
+{
+    return path_;
+}
+
+ShowHistoryCommand::ShowHistoryCommand(const std::string& path)
+    : AppletCommand<void>("show-history"),
+      path_(path)
+{
+}
+
+std::string ShowHistoryCommand::serialize()
+{
+    return path_;
+}
+
+} // namespace seafile
diff --git a/extensions/commands.h b/extensions/commands.h
new file mode 100644 (file)
index 0000000..3a4de9b
--- /dev/null
@@ -0,0 +1,211 @@
+#ifndef SEAFILE_EXTENSION_APPLET_COMMANDS_H
+#define SEAFILE_EXTENSION_APPLET_COMMANDS_H
+
+#include <string>
+#include <vector>
+
+#include "applet-connection.h"
+
+namespace seafile {
+class RepoInfo
+{
+public:
+    enum Status {
+        NoStatus = 0,
+        Paused,
+        Normal,
+        Syncing,
+        Error,
+        LockedByMe,
+        LockedByOthers,
+        ReadOnly,
+        N_Status,
+    };
+
+    std::string repo_id;
+    std::string repo_name;
+    std::string worktree;
+    Status status;
+    bool support_file_lock;
+    bool support_private_share;
+
+    RepoInfo() : status(NoStatus)
+    {
+    }
+
+    RepoInfo(const std::string& repo_id,
+             const std::string repo_name,
+             const std::string& worktree,
+             Status status,
+             bool support_file_lock,
+             bool support_private_share)
+        : repo_id(repo_id),
+          repo_name(repo_name),
+          worktree(worktree),
+          status(status),
+          support_file_lock(support_file_lock),
+          support_private_share(support_private_share)
+    {
+    }
+
+    bool isValid()
+    {
+        return !repo_id.empty();
+    }
+};
+
+std::string toString(RepoInfo::Status st);
+
+typedef std::vector<RepoInfo> RepoInfoList;
+
+/**
+ * Abstract base class for all commands sent to seafile applet.
+ */
+template<class T>
+class AppletCommand {
+public:
+    AppletCommand(std::string name) : name_(name) {}
+
+    /**
+     * send the command to seafile client, don't need the response
+     */
+    void send()
+    {
+        AppletConnection::instance()->sendCommand(formatRequest());
+    }
+
+    std::string formatRequest()
+    {
+        return name_ + "\t" + serialize();
+    }
+
+    /**
+     * send the command to seafile client, and wait for the response
+     */
+    bool sendAndWait(T *resp)
+    {
+        std::string raw_resp;
+        if (!AppletConnection::instance()->sendCommandAndWait(formatRequest(), &raw_resp)) {
+            return false;
+        }
+
+        return parseResponse(raw_resp, resp);
+    }
+
+protected:
+    /**
+     * Prepare this command for sending through the pipe
+     */
+    virtual std::string serialize() = 0;
+
+    /**
+     * Parse response from seafile applet. Commands that don't need the
+     * respnse can inherit the implementation of the base class, which does
+     * nothing.
+     */
+    virtual bool parseResponse(const std::string& raw_resp, T *resp)
+    {
+        return true;
+    }
+
+private:
+    std::string name_;
+};
+
+
+class GetShareLinkCommand : public AppletCommand<void> {
+public:
+    GetShareLinkCommand(const std::string path);
+
+protected:
+    std::string serialize();
+
+private:
+    std::string path_;
+};
+
+class GetInternalLinkCommand : public AppletCommand<void> {
+public:
+    GetInternalLinkCommand(const std::string path);
+
+protected:
+    std::string serialize();
+
+private:
+    std::string path_;
+};
+
+
+class ListReposCommand : public AppletCommand<RepoInfoList> {
+public:
+    ListReposCommand();
+
+protected:
+    std::string serialize();
+
+    bool parseResponse(const std::string& raw_resp, RepoInfoList *worktrees);
+};
+
+class GetFileStatusCommand : public AppletCommand<RepoInfo::Status> {
+public:
+    GetFileStatusCommand(const std::string& repo_id, const std::string& path_in_repo, bool isdir);
+
+protected:
+    std::string serialize();
+
+    bool parseResponse(const std::string& raw_resp, RepoInfo::Status *status);
+
+private:
+    std::string repo_id_;
+    std::string path_in_repo_;
+    bool isdir_;
+};
+
+class LockFileCommand : public AppletCommand<void> {
+public:
+    LockFileCommand(const std::string& path);
+
+protected:
+    std::string serialize();
+
+private:
+    std::string path_;
+};
+
+class UnlockFileCommand : public AppletCommand<void> {
+public:
+    UnlockFileCommand(const std::string& path);
+
+protected:
+    std::string serialize();
+
+private:
+    std::string path_;
+};
+
+class PrivateShareCommand : public AppletCommand<void> {
+public:
+    PrivateShareCommand(const std::string& path, bool to_group);
+
+protected:
+    std::string serialize();
+
+private:
+    std::string path_;
+    bool to_group;
+};
+
+class ShowHistoryCommand : public AppletCommand<void> {
+public:
+    ShowHistoryCommand(const std::string& path);
+
+protected:
+    std::string serialize();
+
+private:
+    std::string path_;
+};
+
+}
+
+#endif // SEAFILE_EXTENSION_APPLET_COMMANDS_H
diff --git a/extensions/context-menu.cpp b/extensions/context-menu.cpp
new file mode 100644 (file)
index 0000000..55c7710
--- /dev/null
@@ -0,0 +1,352 @@
+#include "ext-common.h"
+#include "ext-utils.h"
+#include "shell-ext.h"
+#include "log.h"
+#include "commands.h"
+#include "i18n.h"
+
+#define SEAFILE_TR(x) seafile::getString((x)).c_str()
+
+namespace utils = seafile::utils;
+
+namespace {
+
+bool shouldIgnorePath(const std::string& path)
+{
+    /* Show no menu for drive root, such as C: D: */
+    if (path.size() <= 3) {
+        return TRUE;
+    }
+
+    /* Ignore flash disk, network mounted drive, etc. */
+    if (GetDriveType(path.substr(0, 3).c_str()) != DRIVE_FIXED) {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+const char *kMainMenuName = "Seafile";
+
+}
+
+
+STDMETHODIMP ShellExt::Initialize(LPCITEMIDLIST pIDFolder,
+                                   LPDATAOBJECT pDataObj,
+                                   HKEY  hRegKey)
+{
+    return Initialize_Wrap(pIDFolder, pDataObj, hRegKey);
+}
+
+STDMETHODIMP ShellExt::Initialize_Wrap(LPCITEMIDLIST folder,
+                                        LPDATAOBJECT data,
+                                        HKEY /* hRegKey */)
+{
+    FORMATETC format = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+    STGMEDIUM stg = {TYMED_HGLOBAL, {L'\0'}, NULL};
+    HDROP drop;
+    UINT count;
+    UINT size;
+    HRESULT result = S_OK;
+    wchar_t path_dir_w[4096];
+    std::unique_ptr<wchar_t[]> path_w;
+
+    active_menu_items_.clear();
+
+    /* 'folder' param is not null only when clicking at the foler background;
+       When right click on a file, it's NULL */
+    if (folder) {
+        if (SHGetPathFromIDListW(folder, path_dir_w)) {
+            path_ = utils::normalizedPath(utils::wStringToUtf8(path_dir_w));
+        }
+    }
+
+    /* if 'data' is NULL, then it's a background click, we have set
+     * path_ to folder's name above, and the Init work is done */
+    if (!data)
+        return S_OK;
+
+    /* 'data' is no null, which means we are operating on a file. The
+     * following lines until the end of the function is used to extract the
+     * filename of the current file. */
+    if (FAILED(data->GetData(&format, &stg)))
+        return E_INVALIDARG;
+
+    drop = (HDROP)GlobalLock(stg.hGlobal);
+    if (!drop)
+        return E_INVALIDARG;
+
+    // When the function copies a file name to the buffer, the return value is a
+    // count of the characters copied, not including the terminating null
+    // character.
+    count = DragQueryFileW(drop, 0xFFFFFFFF, NULL, 0);
+    if (count == 0) {
+        result = E_INVALIDARG;
+    } else if (count > 1) {
+        result = S_FALSE;
+    } else {
+        size = DragQueryFileW(drop, 0, NULL, 0);
+        if (!size) {
+            result = E_INVALIDARG;
+        } else {
+            path_w.reset(new wchar_t[size+1]);
+            if (!DragQueryFileW(drop, 0, path_w.get(), size+1))
+                result = E_INVALIDARG;
+        }
+    }
+
+    GlobalUnlock(stg.hGlobal);
+    ReleaseStgMedium(&stg);
+
+    if (result == S_OK) {
+        path_ = utils::normalizedPath(utils::wStringToUtf8(path_w.get()));
+    }
+
+    return result;
+}
+
+STDMETHODIMP ShellExt::QueryContextMenu(HMENU hMenu,
+                                        UINT indexMenu,
+                                        UINT idCmdFirst,
+                                        UINT idCmdLast,
+                                        UINT uFlags)
+{
+    return QueryContextMenu_Wrap(hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
+}
+
+
+STDMETHODIMP ShellExt::QueryContextMenu_Wrap(HMENU menu,
+                                              UINT indexMenu,
+                                              UINT first_command,
+                                              UINT last_command,
+                                              UINT flags)
+{
+    if (!seafile::utils::isShellExtEnabled()) {
+        return S_OK;
+    }
+    /* do nothing when user is double clicking */
+    if (flags & CMF_DEFAULTONLY)
+        return S_OK;
+
+    if (shouldIgnorePath(path_)) {
+        return S_OK;
+    }
+
+    std::string path_in_repo;
+    seafile::RepoInfo repo;
+    if (!pathInRepo(path_, &path_in_repo, &repo) || path_in_repo.size() <= 1) {
+        return S_OK;
+    }
+
+    next_active_item_ = 0;
+
+    main_menu_ = menu;
+    first_ = first_command;
+    last_ = last_command;
+    index_ = 0;
+
+    buildSubMenu(repo, path_in_repo);
+
+    if (!insertMainMenu()) {
+        return S_FALSE;
+    }
+
+    return MAKE_HRESULT(
+        SEVERITY_SUCCESS, FACILITY_NULL, 3 + next_active_item_);
+}
+
+void ShellExt::tweakMenu(HMENU menu)
+{
+    MENUINFO MenuInfo;
+    MenuInfo.cbSize  = sizeof(MenuInfo);
+    MenuInfo.fMask   = MIM_STYLE | MIM_APPLYTOSUBMENUS;
+    MenuInfo.dwStyle = MNS_CHECKORBMP;
+
+    SetMenuInfo(menu, &MenuInfo);
+}
+
+STDMETHODIMP ShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
+{
+    return InvokeCommand_Wrap(lpcmi);
+}
+
+// This is called when you invoke a command on the menu
+STDMETHODIMP ShellExt::InvokeCommand_Wrap(LPCMINVOKECOMMANDINFO info)
+{
+    // see http://stackoverflow.com/questions/11443282/winapi-shell-extension-overriding-windows-command
+    if (HIWORD(info->lpVerb))
+        return E_INVALIDARG;
+
+    if (path_.empty()) {
+        return E_INVALIDARG;
+    }
+
+    UINT id = LOWORD(info->lpVerb);
+    if (id == 0)
+        return S_OK;
+
+    id--;
+    if (id > active_menu_items_.size() - 1) {
+        seaf_ext_log ("invalid menu id %u", id);
+        return S_FALSE;
+    }
+
+    MenuOp op = active_menu_items_[id];
+
+    if (op == GetShareLink) {
+        seafile::GetShareLinkCommand cmd(path_);
+        cmd.send();
+    } else if (op == GetInternalLink) {
+        seafile::GetInternalLinkCommand cmd(path_);
+        cmd.send();
+    } else if (op == LockFile) {
+        seafile::LockFileCommand cmd(path_);
+        cmd.send();
+    } else if (op == UnlockFile) {
+        seafile::UnlockFileCommand cmd(path_);
+        cmd.send();
+    } else if (op == ShareToUser) {
+        seafile::PrivateShareCommand cmd(path_, false);
+        cmd.send();
+    } else if (op == ShareToGroup) {
+        seafile::PrivateShareCommand cmd(path_, true);
+        cmd.send();
+    } else if (op == ShowHistory) {
+        seafile::ShowHistoryCommand cmd(path_);
+        cmd.send();
+    }
+
+    return S_OK;
+}
+
+STDMETHODIMP ShellExt::GetCommandString(UINT_PTR idCmd,
+                                         UINT flags,
+                                         UINT FAR * reserved,
+                                         LPSTR pszName,
+                                         UINT cchMax)
+{
+    return GetCommandString_Wrap(idCmd, flags, reserved, pszName, cchMax);
+}
+
+// This is for the status bar and things like that:
+STDMETHODIMP ShellExt::GetCommandString_Wrap(UINT_PTR idCmd,
+                                              UINT flags,
+                                              UINT FAR * /*reserved*/,
+                                              LPSTR pszName,
+                                              UINT cchMax)
+{
+    lstrcpynW((LPWSTR)pszName, L"This is Seafile help string.", cchMax);
+    return S_OK;
+}
+
+STDMETHODIMP ShellExt::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    return HandleMenuMsg_Wrap(uMsg, wParam, lParam);
+}
+
+STDMETHODIMP ShellExt::HandleMenuMsg_Wrap(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    LRESULT res;
+    return HandleMenuMsg2(uMsg, wParam, lParam, &res);
+}
+
+STDMETHODIMP ShellExt::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult)
+{
+    return HandleMenuMsg2_Wrap(uMsg, wParam, lParam, pResult);
+}
+
+STDMETHODIMP ShellExt::HandleMenuMsg2_Wrap(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult)
+{
+    return S_OK;
+}
+
+/**
+ * Add two menu seperators, with seafile menu between them
+ */
+bool ShellExt::insertMainMenu()
+{
+    // Insert a seperate before seafile menu
+    if (!InsertMenu(main_menu_, index_++, MF_BYPOSITION |MF_SEPARATOR, 0, ""))
+        return FALSE;
+
+    MENUITEMINFO menuiteminfo;
+    ZeroMemory(&menuiteminfo, sizeof(menuiteminfo));
+    menuiteminfo.cbSize = sizeof(menuiteminfo);
+    menuiteminfo.fMask = MIIM_FTYPE | MIIM_SUBMENU | MIIM_STRING | MIIM_ID;
+    menuiteminfo.fType = MFT_STRING;
+    menuiteminfo.dwTypeData = (char*)kMainMenuName;
+    menuiteminfo.cch = strlen(kMainMenuName);
+    // menuiteminfo.hbmpItem = HBMMENU_CALLBACK;
+    menuiteminfo.hSubMenu = sub_menu_;
+    menuiteminfo.wID = first_;
+
+    if (!InsertMenuItem(main_menu_, index_++, TRUE, &menuiteminfo))
+        return FALSE;
+
+    // Insert a seperate after seafile menu
+    if (!InsertMenu(main_menu_, index_++, MF_BYPOSITION |MF_SEPARATOR, 0, ""))
+        return FALSE;
+
+    /* Set menu styles of submenu */
+    tweakMenu(main_menu_);
+
+    return TRUE;
+}
+
+MENUITEMINFO
+ShellExt::createMenuItem(const std::string& text)
+{
+    MENUITEMINFO minfo;
+    memset(&minfo, 0, sizeof(minfo));
+    minfo.cbSize = sizeof(MENUITEMINFO);
+    minfo.fMask = MIIM_FTYPE | MIIM_BITMAP | MIIM_STRING | MIIM_ID;
+    minfo.fType = MFT_STRING;
+    minfo.dwTypeData = (char *)text.c_str();
+    minfo.cch = text.size();
+    minfo.hbmpItem = HBMMENU_CALLBACK;
+    minfo.wID = first_ + 1 + next_active_item_++;
+
+    return minfo;
+}
+
+void ShellExt::insertSubMenuItem(const std::string& text, MenuOp op)
+{
+    MENUITEMINFO minfo;
+    minfo = createMenuItem(text);
+    InsertMenuItem (sub_menu_, /* menu */
+                    index_++,  /* position */
+                    TRUE,      /* by position */
+                    &minfo);
+    active_menu_items_.push_back(op);
+}
+
+
+void ShellExt::buildSubMenu(const seafile::RepoInfo& repo,
+                            const std::string& path_in_repo)
+{
+    insertSubMenuItem(SEAFILE_TR("get seafile download link"), GetShareLink);
+    insertSubMenuItem(SEAFILE_TR("get seafile internal link"), GetInternalLink);
+
+    std::unique_ptr<wchar_t[]> path_w(utils::utf8ToWString(path_));
+    bool is_dir = GetFileAttributesW(path_w.get()) & FILE_ATTRIBUTE_DIRECTORY;
+    if (repo.support_private_share && is_dir) {
+        insertSubMenuItem(SEAFILE_TR("share to a user"), ShareToUser);
+        insertSubMenuItem(SEAFILE_TR("share to a group"), ShareToGroup);
+    }
+
+    if (repo.support_file_lock && !is_dir) {
+        seafile::RepoInfo::Status status =
+            getRepoFileStatus(repo.repo_id, path_in_repo, false);
+
+        if (status == seafile::RepoInfo::LockedByMe) {
+            insertSubMenuItem(SEAFILE_TR("unlock this file"), UnlockFile);
+        }
+        else if (status != seafile::RepoInfo::LockedByOthers) {
+            insertSubMenuItem(SEAFILE_TR("lock this file"), LockFile);
+        }
+    }
+
+    if (!is_dir) {
+        insertSubMenuItem(SEAFILE_TR("view file history"), ShowHistory);
+    }
+}
diff --git a/extensions/debug-register.reg b/extensions/debug-register.reg
new file mode 100644 (file)
index 0000000..cd85d3a
--- /dev/null
@@ -0,0 +1,112 @@
+Windows Registry Editor Version 5.00
+
+# context menu handler
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"="Seafile"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}]
+@="Seafile"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\Seafile]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\*\shellex\ContextMenuHandlers\Seafile]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"
+
+[HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers\Seafile]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"
+
+[HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers\Seafile]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"
+
+[HKEY_CLASSES_ROOT\Folder\shellex\ContextMenuHandlers\Seafile]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"
+
+# Icon Overlay 1 (normal repo icon)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}"="SeafileIconNormal"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}]
+@="SeafileIconNormal"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconNormal"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}"
+
+
+# Icon Overlay 2 (syncing icon)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}"="SeafileIconSyncing"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}]
+@="SeafileIconSyncing"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconSyncing"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}"
+
+# Icon Overlay 3 (error icon)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}"="SeafileIconError"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}]
+@="SeafileIconError"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconError"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}"
+
+# Icon Overlay 4 (paused icon)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}"="SeafileIconPaused"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}]
+@="SeafileIconPaused"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconPaused"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}"
+
+# Icon Overlay 5 (locked by me)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}"="SeafileIconLockedByMe"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}]
+@="SeafileIconLockedByMe"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconLockedByMe"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}"
+
+# Icon Overlay 6 (locked by others)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}"="SeafileIconLockedByOthers"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}]
+@="SeafileIconLockedByOthers"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconLockedByOthers"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}"
\ No newline at end of file
diff --git a/extensions/debug-unregister.reg b/extensions/debug-unregister.reg
new file mode 100644 (file)
index 0000000..0436606
--- /dev/null
@@ -0,0 +1,83 @@
+Windows Registry Editor Version 5.00
+
+# approved ext
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"=-
+
+# register shell extension
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Seafile]
+
+# context menu handler
+[-HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\Seafile]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\*\shellex\ContextMenuHandlers\Seafile]
+
+[-HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers\Seafile]
+
+[-HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers\Seafile]
+
+[-HKEY_CLASSES_ROOT\Folder\shellex\ContextMenuHandlers\Seafile]
+
+# Icon Overlay IconNormal
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconNormal"]
+
+# Icon Overlay IconSyncing
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconSyncing"]
+
+# Icon Overlay IconError
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconError"]
+
+# Icon Overlay IconPaused
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconPaused"]
+
+# Icon Overlay IconLockedByMe
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconLockedByMe"]
+
+# Icon Overlay IconLockedByOthers
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconLockedByOthers"]
\ No newline at end of file
diff --git a/extensions/dll.cpp b/extensions/dll.cpp
new file mode 100644 (file)
index 0000000..4206dfe
--- /dev/null
@@ -0,0 +1,97 @@
+
+#include "ext-common.h"
+#include "class-factory.h"
+#include "applet-connection.h"
+#include "guids.h"
+#include "log.h"
+#include "ext-utils.h"
+
+#include "shell-ext.h"
+
+volatile LONG       g_cRefThisDll = 0;              ///< reference count of this DLL.
+HINSTANCE           g_hmodThisDll = NULL;           ///< handle to this DLL itself.
+int                 g_cAprInit = 0;
+DWORD               g_langid;
+DWORD               g_langTimeout = 0;
+HINSTANCE           g_hResInst = NULL;
+
+extern "C" int APIENTRY
+DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReserved */)
+{
+    if (dwReason == DLL_PROCESS_ATTACH)
+    {
+        if (g_hmodThisDll == NULL)
+        {
+            // g_csGlobalCOMGuard.Init();
+        }
+
+        // Extension DLL one-time initialization
+        g_hmodThisDll = hInstance;
+        seafile::AppletConnection::instance()->prepare();
+    }
+    else if (dwReason == DLL_PROCESS_DETACH)
+    {
+        // do not clean up memory here:
+        // if an application doesn't release all COM objects
+        // but still unloads the dll, cleaning up ourselves
+        // will lead to crashes.
+        // better to leak some memory than to crash other apps.
+        // sometimes an application doesn't release all COM objects
+        // but still unloads the dll.
+        // in that case, we do it ourselves
+
+        // g_csGlobalCOMGuard.Term();
+    }
+    return 1;   // ok
+}
+
+STDAPI DllCanUnloadNow(void)
+{
+    return (g_cRefThisDll == 0 ? S_OK : S_FALSE);
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)
+{
+    if (ppvOut == 0)
+        return E_POINTER;
+    *ppvOut = NULL;
+
+    if (IsEqualIID(rclsid, CLSID_SEAFILE_SHELLEXT)) {
+        ShellExtClassFactory *pcf = new ShellExtClassFactory;
+        const HRESULT hr = pcf->QueryInterface(riid, ppvOut);
+        if(FAILED(hr))
+            delete pcf;
+        return hr;
+    }
+
+    seafile::RepoInfo::Status status = seafile::RepoInfo::NoStatus;
+    if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_NORMAL)) {
+        // seaf_ext_log ("DllGetClassObject called for ICON_NORMAL!");
+        status = seafile::RepoInfo::Normal;
+    } else if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_SYNCING)) {
+        // seaf_ext_log ("DllGetClassObject called for ICON_SYNCING!");
+        status = seafile::RepoInfo::Syncing;
+    } else if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_ERROR)) {
+        // seaf_ext_log ("DllGetClassObject called for ICON_ERROR!");
+        status = seafile::RepoInfo::Error;
+    } else if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_PAUSED)) {
+        // seaf_ext_log ("DllGetClassObject called for ICON_PAUSED!");
+        status = seafile::RepoInfo::Paused;
+    } else if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_LOCKED_BY_ME)) {
+        // seaf_ext_log ("DllGetClassObject called for ICON_LOCKED_BY_ME!");
+        status = seafile::RepoInfo::LockedByMe;
+    } else if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_LOCKED_BY_OTHERS)) {
+        // seaf_ext_log ("DllGetClassObject called for ICON_LOCKED_BY_OTHERS!");
+        status = seafile::RepoInfo::LockedByOthers;
+    }
+
+    if (status != seafile::RepoInfo::NoStatus) {
+        ShellExtClassFactory *pcf = new ShellExtClassFactory(status);
+        const HRESULT hr = pcf->QueryInterface(riid, ppvOut);
+        if(FAILED(hr))
+            delete pcf;
+        return hr;
+    }
+
+    return CLASS_E_CLASSNOTAVAILABLE;
+}
diff --git a/extensions/error.ico b/extensions/error.ico
new file mode 100644 (file)
index 0000000..75d5055
Binary files /dev/null and b/extensions/error.ico differ
diff --git a/extensions/ext-common.h b/extensions/ext-common.h
new file mode 100644 (file)
index 0000000..45dae20
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef SEAFILE_EXT_EXT_COMMON_H
+#define SEAFILE_EXT_EXT_COMMON_H
+
+// This header should be the first include of each cpp source file
+
+// A workaround for some mingw problem.
+// See http://stackoverflow.com/questions/3445312/swprintf-and-vswprintf-not-declared
+#undef __STRICT_ANSI__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#include <commctrl.h>
+
+#include <shlobj.h>
+#include <shlguid.h>
+#include <wininet.h>
+#include <aclapi.h>
+
+#endif // SEAFILE_EXT_EXT_COMMON_H
diff --git a/extensions/ext-utils.cpp b/extensions/ext-utils.cpp
new file mode 100644 (file)
index 0000000..303e528
--- /dev/null
@@ -0,0 +1,511 @@
+#include "ext-common.h"
+#include <io.h>
+#include <shellapi.h>
+#include <shlwapi.h>
+#include <fcntl.h>
+#include <psapi.h>
+#include <ctype.h>
+#include <userenv.h>
+
+#include <sstream>
+#include <algorithm>
+#include <memory>
+
+#include "log.h"
+#include "ext-utils.h"
+#include "shell-ext.h"
+
+namespace {
+
+const int kPipeWaitTimeMSec = 1000;
+
+class OverLappedWrapper
+{
+public:
+    OverLappedWrapper() {
+        memset(&ol_, 0, sizeof(ol_));
+        ol_.Offset = ol_.OffsetHigh = 0;
+        HANDLE h_ev = CreateEvent
+            (NULL,                  /* security attribute */
+             FALSE,                 /* manual reset */
+             FALSE,                 /* initial state  */
+             NULL);                 /* event name */
+
+        ol_.hEvent = h_ev;
+    }
+
+    ~OverLappedWrapper() {
+        CloseHandle(ol_.hEvent);
+    }
+
+    OVERLAPPED *get() { return &ol_; }
+
+private:
+    OVERLAPPED ol_;
+};
+
+} // namespace
+
+namespace seafile {
+namespace utils {
+
+
+Mutex::Mutex()
+{
+    handle_ = CreateMutex
+        (NULL,                  /* securitry attr */
+         FALSE,                 /* own the mutex immediately after create */
+         NULL);                 /* name */
+}
+
+Mutex::~Mutex()
+{
+    CloseHandle(handle_);
+}
+
+void Mutex::lock()
+{
+    while (1) {
+        DWORD ret = WaitForSingleObject(handle_, INFINITE);
+        if (ret == WAIT_OBJECT_0)
+            return;
+    }
+}
+
+void Mutex::unlock()
+{
+    ReleaseMutex(handle_);
+}
+
+MutexLocker::MutexLocker(Mutex *mutex)
+    : mu_(mutex)
+{
+    mu_->lock();
+}
+
+MutexLocker::~MutexLocker()
+{
+    mu_->unlock();
+}
+
+
+void regulatePath(char *p)
+{
+    if (!p)
+        return;
+
+    char *s = p;
+    /* Use capitalized C/D/E, etc. */
+    if (s[0] >= 'a')
+        s[0] = toupper(s[0]);
+
+    /* Use / instead of \ */
+    while (*s) {
+        if (*s == '\\')
+            *s = '/';
+        s++;
+    }
+
+    s--;
+    /* strip trailing white spaces and path seperator */
+    while (isspace(*s) || *s == '/') {
+        *s = '\0';
+        s--;
+    }
+}
+
+std::string getHomeDir()
+{
+    static char *home;
+
+    if (home)
+        return home;
+
+    char buf[MAX_PATH] = {'\0'};
+
+    if (!home) {
+        /* Try env variable first. */
+        GetEnvironmentVariable("HOME", buf, MAX_PATH);
+        if (buf[0] != '\0')
+            home = strdup(buf);
+    }
+
+    if (!home) {
+        /* No `HOME' ENV; Try user profile */
+        HANDLE hToken = NULL;
+        DWORD len = MAX_PATH;
+        if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
+            GetUserProfileDirectory (hToken, buf, &len);
+            CloseHandle(hToken);
+            if (buf[0] != '\0')
+                home = strdup(buf);
+        }
+    }
+
+    if (home)
+        regulatePath(home);
+    return home ? home : "";
+}
+
+bool
+doPipeWait (HANDLE pipe, OVERLAPPED *ol, DWORD len)
+{
+    DWORD bytes_rw, result;
+    result = WaitForSingleObject (ol->hEvent, kPipeWaitTimeMSec);
+    if (result == WAIT_OBJECT_0) {
+        if (!GetOverlappedResult(pipe, ol, &bytes_rw, false)
+            || bytes_rw != len) {
+            seaf_ext_log ("async read failed: %s",
+                            formatErrorMessage().c_str());
+            return false;
+        }
+    } else if (result == WAIT_TIMEOUT) {
+        seaf_ext_log ("connection timeout");
+        return false;
+
+    } else {
+        seaf_ext_log ("failed to communicate with seafil client: %s",
+                      formatErrorMessage().c_str());
+        return false;
+    }
+
+    return true;
+}
+
+bool
+checkLastError()
+{
+    DWORD last_error = GetLastError();
+    if (last_error != ERROR_IO_PENDING && last_error != ERROR_SUCCESS) {
+        if (last_error == ERROR_BROKEN_PIPE || last_error == ERROR_NO_DATA
+            || last_error == ERROR_PIPE_NOT_CONNECTED) {
+            seaf_ext_log ("connection broken with error: %s",
+                          formatErrorMessage().c_str());
+        } else {
+            seaf_ext_log ("failed to communicate with seafile client: %s",
+                          formatErrorMessage().c_str());
+        }
+        return false;
+    }
+    return true;
+}
+
+bool
+pipeReadN (HANDLE pipe,
+           void *buf,
+           uint32_t len)
+{
+    OverLappedWrapper ol;
+    bool ret= ReadFile(
+        pipe,                  // handle to pipe
+        buf,                    // buffer to write from
+        (DWORD)len,             // number of bytes to read
+        NULL,                   // number of bytes read
+        ol.get());              // overlapped (async) IO
+
+    if (!ret && !checkLastError()) {
+        return false;
+    }
+
+    if (!doPipeWait (pipe, ol.get(), (DWORD)len)) {
+        return false;
+    }
+
+    return true;
+}
+
+bool
+pipeWriteN(HANDLE pipe,
+           const void *buf,
+           uint32_t len)
+{
+    OverLappedWrapper ol;
+    bool ret = WriteFile(
+        pipe,                   // handle to pipe
+        buf,                    // buffer to write from
+        (DWORD)len,             // number of bytes to write
+        NULL,                   // number of bytes written
+        ol.get());              // overlapped (async) IO
+
+    if (!ret && !checkLastError()) {
+        return false;
+    }
+
+    if (!doPipeWait(pipe, ol.get(), (DWORD)len))
+        return false;
+
+    return true;
+}
+
+bool doInThread(LPTHREAD_START_ROUTINE func, void *data)
+{
+    DWORD tid = 0;
+    HANDLE thread = CreateThread
+        (NULL,                  /* security attr */
+         0,                     /* stack size, 0 for default */
+         func,                  /* start address */
+         (void *)data,          /* param*/
+         0,                     /* creation flags */
+         &tid);                 /* thread ID */
+
+    if (!thread) {
+        seaf_ext_log ("failed to create thread");
+        return false;
+    }
+
+    CloseHandle(thread);
+    return true;
+}
+
+// http://stackoverflow.com/questions/3006229/get-a-text-from-the-error-code-returns-from-the-getlasterror-function
+std::string formatErrorMessage()
+{
+    DWORD error_code = ::GetLastError();
+    if (error_code == 0) {
+        return "no error";
+    }
+    char buf[256] = {0};
+    ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+                    NULL,
+                    error_code,
+                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                    buf,
+                    sizeof(buf) - 1,
+                    NULL);
+    return buf;
+}
+
+std::vector<std::string> split(const std::string &s, char delim)
+{
+    std::vector<std::string> elems;
+    std::stringstream ss(s);
+    std::string item;
+    while (std::getline(ss, item, delim) && !item.empty()) {
+        elems.push_back(item);
+    }
+    return elems;
+}
+
+std::string normalizedPath(const std::string& path)
+{
+    std::string p = path;
+    std::replace(p.begin(), p.end(), '\\', '/');
+    while (!p.empty() && p[p.size() - 1] == '/') {
+        p = p.substr(0, p.size() - 1);
+    }
+    return p;
+}
+
+uint64_t currentMSecsSinceEpoch()
+{
+    SYSTEMTIME st;
+    FILETIME ft;
+    GetSystemTime(&st);
+    SystemTimeToFileTime(&st, &ft);
+
+    ULARGE_INTEGER u;
+    u.LowPart  = ft.dwLowDateTime;
+    u.HighPart = ft.dwHighDateTime;
+
+    // See http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux
+#define TICKS_PER_MSEC 10000
+#define EPOCH_DIFFERENCE 11644473600000LL
+    uint64_t temp;
+    temp = u.QuadPart / TICKS_PER_MSEC; //convert from 100ns intervals to milli seconds;
+    temp = temp - EPOCH_DIFFERENCE; //subtract number of seconds between epochs
+    return temp;
+}
+
+std::string splitPath(const std::string& path, int *pos)
+{
+    if (path.size() == 0) {
+        return "";
+    }
+
+    std::string p = normalizedPath(path);
+    while (p.size() > 1 && p[-1] == '/') {
+        p = p.substr(0, p.size() - 1);
+    }
+    if (p.size() == 1) {
+        return p;
+    }
+
+    *pos = p.rfind("/");
+    return p;
+}
+
+
+std::string getParentPath(const std::string& path)
+{
+    int pos;
+    std::string p = splitPath(path, &pos);
+    if (p.size() <= 1) {
+        return p;
+    }
+
+    if (pos == -1)
+        return "";
+    if (pos == 0)
+        return "/";
+    return p.substr(0, pos);
+}
+
+std::string getBaseName(const std::string& path)
+{
+    int pos;
+    std::string p = splitPath(path, &pos);
+    if (p.size() <= 1) {
+        return p;
+    }
+
+    if (pos == -1) {
+        return p;
+    }
+    return p.substr(pos, p.size() - pos);
+}
+
+std::string getThisDllPath()
+{
+    static char module_filename[MAX_PATH] = { 0 };
+
+    if (module_filename[0] == '\0') {
+        DWORD module_size;
+        module_size = GetModuleFileName(
+            g_hmodThisDll, module_filename, MAX_PATH);
+        if (!module_size)
+            return "";
+
+        normalizedPath(module_filename);
+    }
+
+    return module_filename;
+}
+
+std::string getThisDllFolder()
+{
+    std::string dll = getThisDllPath();
+
+    return dll.empty() ? "" : getParentPath(dll);
+}
+
+wchar_t *localeToWString(const std::string& src)
+{
+    wchar_t dst[4096];
+    int len;
+
+    len = MultiByteToWideChar
+        (CP_ACP,                /* multibyte code page */
+         0,                     /* flags */
+         src.c_str(),           /* src */
+         -1,                    /* src len, -1 for all includes \0 */
+         dst,                   /* dst */
+         sizeof(dst) / sizeof(wchar_t));          /* dst buf len */
+
+    if (len <= 0) {
+        return NULL;
+    }
+
+    return wcsdup(dst);
+}
+
+
+std::string wStringToLocale(const wchar_t *src)
+{
+    char dst[4096];
+    int len;
+
+    len = WideCharToMultiByte
+        (CP_ACP,        /* multibyte code page */
+         0,             /* flags */
+         src,           /* src */
+         -1,            /* src len, -1 for all includes \0 */
+         dst,           /* dst */
+         sizeof(dst),   /* dst buf len */
+         NULL,          /* default char */
+         NULL);         /* BOOL flag indicates default char is used */
+
+    if (len <= 0) {
+        return "";
+    }
+
+    return dst;
+}
+
+std::string wStringToUtf8(const wchar_t *src)
+{
+    char dst[4096];
+    int len;
+
+    len = WideCharToMultiByte
+        (CP_UTF8,               /* multibyte code page */
+         0,                     /* flags */
+         src,                   /* src */
+         -1,                    /* src len, -1 for all includes \0 */
+         dst,                   /* dst */
+         sizeof(dst),           /* dst buf len */
+         NULL,                  /* default char */
+         NULL);                 /* BOOL flag indicates default char is used */
+
+    if (len <= 0) {
+        return "";
+    }
+
+    return dst;
+}
+
+wchar_t *utf8ToWString(const std::string& src)
+{
+    wchar_t dst[4096];
+    int len;
+
+    len = MultiByteToWideChar
+        (CP_UTF8,                        /* multibyte code page */
+         0,                              /* flags */
+         src.c_str(),                    /* src */
+         -1,                             /* src len, -1 for all includes \0 */
+         dst,                            /* dst */
+         sizeof(dst) / sizeof(wchar_t)); /* dst buf len */
+
+    if (len <= 0) {
+        return NULL;
+    }
+
+    return wcsdup(dst);
+}
+
+bool isShellExtEnabled()
+{
+    // TODO: This function is called very frequently. Consider caching the
+    // result in memory for a few seconds, and only query the registry after
+    // that.
+    HKEY root = HKEY_CURRENT_USER;
+    HKEY parent_key;
+    wchar_t *software_seafile = localeToWString("Software\\Seafile");
+    LONG result = RegOpenKeyExW(root,
+                                software_seafile,
+                                0L,
+                                KEY_ALL_ACCESS,
+                                &parent_key);
+    free(software_seafile);
+    if (result != ERROR_SUCCESS) {
+        return true;
+    }
+
+    char buf[MAX_PATH] = {0};
+    DWORD len = sizeof(buf);
+    wchar_t *shell_ext_disabled = localeToWString("ShellExtDisabled");
+    result = RegQueryValueExW (parent_key,
+                               shell_ext_disabled,
+                               NULL,             /* reserved */
+                               NULL,             /* output type */
+                               (LPBYTE)buf,      /* output data */
+                               &len);            /* output length */
+    RegCloseKey(parent_key);
+    free(shell_ext_disabled);
+
+    return result != ERROR_SUCCESS;
+}
+
+
+} // namespace utils
+} // namespace seafile
diff --git a/extensions/ext-utils.h b/extensions/ext-utils.h
new file mode 100644 (file)
index 0000000..cbb1469
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef SEAFILE_EXTENSION_EXT_UTILS_H
+#define SEAFILE_EXTENSION_EXT_UTILS_H
+
+#include <string>
+#include <vector>
+#include <stdint.h>
+
+namespace seafile {
+namespace utils {
+
+class Mutex {
+public:
+    Mutex();
+    ~Mutex();
+
+    void lock();
+    void unlock();
+
+private:
+    Mutex(const Mutex& rhs);
+    HANDLE handle_;
+};
+
+class MutexLocker {
+public:
+    MutexLocker(Mutex *mutex);
+    ~MutexLocker();
+
+private:
+    Mutex *mu_;
+};
+
+std::string getHomeDir();
+
+/**
+ * Translate the error code of GetLastError() to a human readable message.
+ */
+std::string formatErrorMessage();
+
+bool pipeReadN (HANDLE hPipe,
+                void *buf,
+                uint32_t len);
+
+bool pipeWriteN (HANDLE hPipe,
+                 const void *buf,
+                 uint32_t len);
+
+bool doInThread(LPTHREAD_START_ROUTINE func, void *data);
+
+std::vector<std::string> split(const std::string &s, char delim);
+
+std::string normalizedPath(const std::string& path);
+
+uint64_t currentMSecsSinceEpoch();
+
+wchar_t *localeToWString(const std::string& src);
+std::string wStringToLocale(const wchar_t *src);
+
+wchar_t *utf8ToWString(const std::string& src);
+std::string wStringToUtf8(const wchar_t *src);
+
+std::string getBaseName(const std::string& path);
+std::string getParentPath(const std::string& path);
+
+std::string getThisDllFolder();
+std::string getThisDllPath();
+
+bool isShellExtEnabled();
+
+} // namespace utils
+} // namespace seafile
+
+#endif // SEAFILE_EXTENSION_EXT_UTILS_H
diff --git a/extensions/guids.h b/extensions/guids.h
new file mode 100644 (file)
index 0000000..c217c60
--- /dev/null
@@ -0,0 +1,21 @@
+// The class IDs of these Shell extension class.
+//
+// class ids:
+//
+// D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606
+//
+//
+
+DEFINE_GUID(CLSID_SEAFILE_SHELLEXT,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x06);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_NORMAL,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x07);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_SYNCING,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x08);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_ERROR,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x09);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_PAUSED,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x10);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_LOCKED_BY_ME,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x11);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_LOCKED_BY_OTHERS,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x12);
diff --git a/extensions/i18n.cpp b/extensions/i18n.cpp
new file mode 100644 (file)
index 0000000..f8e95d2
--- /dev/null
@@ -0,0 +1,100 @@
+#include "ext-common.h"
+#include "ext-utils.h"
+
+#include <string>
+#include <map>
+#include <memory>
+
+using std::string;
+
+namespace {
+
+string getWin32Locale()
+{
+  LCID lcid;
+  char iso639[10];
+
+  lcid = GetThreadLocale ();
+
+  if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)))
+      return "C";
+
+  return iso639;
+}
+
+class I18NHelper {
+public:
+    static I18NHelper *instance();
+
+    string getString(const string& src) const;
+
+private:
+    I18NHelper();
+    static I18NHelper *singleton_;
+
+    void initChineseDict();
+    void initGermanDict();
+
+    std::map<string, string> lang_dict_;
+};
+
+
+I18NHelper* I18NHelper::singleton_;
+
+I18NHelper *I18NHelper::instance() {
+    if (!singleton_) {
+        singleton_ = new I18NHelper();
+    }
+    return singleton_;
+}
+
+void I18NHelper::initChineseDict()
+{
+    lang_dict_["get seafile download link"] = "获取共享链接";
+    lang_dict_["get seafile internal link"] = "获取内部链接";
+    lang_dict_["lock this file"] = "锁定该文件";
+    lang_dict_["unlock this file"] = "解锁该文件";
+    lang_dict_["share to a user"] = "共享给其他用户";
+    lang_dict_["share to a group"] = "共享给群组";
+    lang_dict_["view file history"] = "查看文件历史";
+}
+
+void I18NHelper::initGermanDict()
+{
+    lang_dict_["get seafile download link"] = "Freigabelink erstellen";
+    lang_dict_["get seafile internal link"] = "Internen Link erstellen";
+    lang_dict_["lock this file"] = "Datei sperren";
+    lang_dict_["unlock this file"] = "Datei entsperren";
+    lang_dict_["share to a user"] = "Freigabe für Benutzer/in";
+    lang_dict_["share to a group"] = "Freigabe für Gruppe";
+    lang_dict_["view file history"] = "Vorgängerversionen";
+}
+
+I18NHelper::I18NHelper()
+{
+    string locale = getWin32Locale();
+    if (locale == "zh") {
+        initChineseDict();
+    } else if (locale == "de") {
+        initGermanDict();
+    }
+}
+
+string I18NHelper::getString(const string& src) const
+{
+    auto value = lang_dict_.find(src);
+    return value != lang_dict_.end() ? value->second : src;
+}
+
+} // namespace
+
+namespace seafile {
+
+string getString(const string& src)
+{
+    string value = I18NHelper::instance()->getString(src);
+    std::unique_ptr<wchar_t[]> value_w(utils::utf8ToWString(value));
+    return utils::wStringToLocale(value_w.get());
+}
+
+}
diff --git a/extensions/i18n.h b/extensions/i18n.h
new file mode 100644 (file)
index 0000000..3ee7705
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SEAFILE_EXT_I18N_H
+#define SEAFILE_EXT_I18N_H
+
+#include <string>
+
+namespace seafile {
+
+std::string getString(const std::string& src);
+
+} // namespace seafile
+
+#endif // SEAFILE_EXT_I18N_H
diff --git a/extensions/icon-overlay.cpp b/extensions/icon-overlay.cpp
new file mode 100644 (file)
index 0000000..12aac7c
--- /dev/null
@@ -0,0 +1,118 @@
+#include "ext-common.h"
+#include "ext-utils.h"
+#include "shell-ext.h"
+#include "log.h"
+#include "commands.h"
+
+#include <string>
+
+namespace utils = seafile::utils;
+
+// "The Shell calls IShellIconOverlayIdentifier::GetOverlayInfo to request the
+//  location of the handler's icon overlay. The icon overlay handler returns
+//  the name of the file containing the overlay image, and its index within
+//  that file. The Shell then adds the icon overlay to the system image list."
+
+STDMETHODIMP ShellExt::GetOverlayInfo(LPWSTR pwszIconFile, int cchMax, int* pIndex, DWORD* pdwFlags)
+{
+    // seaf_ext_log ("GetOverlayInfo called for icon type %d!", (int)status_);
+
+    std::string dll = utils::getThisDllPath();
+
+    std::unique_ptr<wchar_t[]> ico(utils::localeToWString(dll));
+    int wlen = wcslen(ico.get());
+    if (wlen + 1 > cchMax)
+        return S_FALSE;
+
+    wmemcpy(pwszIconFile, ico.get(), wlen + 1);
+
+    *pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
+
+    *pIndex = (int)status_ - 1;
+
+    return S_OK;
+}
+
+STDMETHODIMP ShellExt::GetPriority(int *priority)
+{
+    /* The priority value can be 0 ~ 100, with 0 be the highest */
+    *priority = seafile::RepoInfo::N_Status - status_;
+    return S_OK;
+}
+
+
+// "Before painting an object's icon, the Shell passes the object's name to
+//  each icon overlay handler's IShellIconOverlayIdentifier::IsMemberOf
+//  method. If a handler wants to have its icon overlay displayed,
+//  it returns S_OK. The Shell then calls the handler's
+//  IShellIconOverlayIdentifier::GetOverlayInfo method to determine which icon
+//  to display."
+
+STDMETHODIMP ShellExt::IsMemberOf(LPCWSTR path_w, DWORD attr)
+{
+    if (!seafile::utils::isShellExtEnabled()) {
+        return S_FALSE;
+    }
+
+    std::string path = utils::wStringToUtf8(path_w);
+    if (!path.size()) {
+        seaf_ext_log ("convert to char failed");
+        return S_FALSE;
+    }
+
+    // seaf_ext_log ("IsMemberOf called for %s, is dir: %s", path.c_str(),
+    //               (attr & FILE_ATTRIBUTE_DIRECTORY) ? "yes": "no");
+
+    /* If length of path is shorter than 3, it should be a drive path,
+     * such as C:\ , which should not be a repo folder ; And the
+     * current folder being displayed must be "My Computer". If we
+     * don't return quickly, it will lag the display.
+     */
+    if (path.size() <= 3) {
+        return S_FALSE;
+    }
+
+    // if (access(path.c_str(), F_OK) < 0 ||
+    //     !(GetFileAttributes(path.c_str()) & FILE_ATTRIBUTE_DIRECTORY)) {
+    //     return S_FALSE;
+    // }
+
+    std::string path_in_repo;
+    seafile::RepoInfo repo;
+    if (!pathInRepo(path, &path_in_repo, &repo)) {
+        // seaf_ext_log ("pathInRepo returns false for %s\n", path.c_str());
+        return S_FALSE;
+    }
+
+    // seaf_ext_log ("path in repo: %s\n", path_in_repo.c_str());
+
+    if (path_in_repo.size() <= 1) {
+        // it's a repo top folder
+        path_in_repo = "";
+    }
+
+    // Now we know it's a file inside the repo
+
+    // TODO: Improve this if we later make the extension<->applet communication full duplex
+    // if (repo.status == seafile::RepoInfo::Paused) {
+    //     return S_FALSE;
+    // }
+
+    // if (repo.status == seafile::RepoInfo::Normal && repo.status == status_) {
+    //     return S_OK;
+    // }
+
+    // Then check the file status.
+    seafile::RepoInfo::Status status = getRepoFileStatus(
+        repo.repo_id, path_in_repo, attr & FILE_ATTRIBUTE_DIRECTORY);
+
+    if (status == seafile::RepoInfo::Paused && !path_in_repo.empty()) {
+        return S_FALSE;
+    }
+    if (status == status_ || (status_ == seafile::RepoInfo::Paused && status == seafile::RepoInfo::ReadOnly)) {
+        // seaf_ext_log ("[ICON] file icon %d: %s", (int)status_, path.c_str());
+        return S_OK;
+    }
+
+    return S_FALSE;
+}
diff --git a/extensions/locked-by-me.ico b/extensions/locked-by-me.ico
new file mode 100755 (executable)
index 0000000..c968367
Binary files /dev/null and b/extensions/locked-by-me.ico differ
diff --git a/extensions/locked-by-others.ico b/extensions/locked-by-others.ico
new file mode 100755 (executable)
index 0000000..8e6380e
Binary files /dev/null and b/extensions/locked-by-others.ico differ
diff --git a/extensions/log.cpp b/extensions/log.cpp
new file mode 100644 (file)
index 0000000..d65a8c5
--- /dev/null
@@ -0,0 +1,84 @@
+#include "ext-common.h"
+#include <time.h>
+#include <stdarg.h>
+
+#include "ext-utils.h"
+#include "log.h"
+
+namespace {
+
+static FILE *log_fp;
+
+std::string getLogPath()
+{
+    std::string home = seafile::utils::getHomeDir();
+    if (home.empty())
+        return "";
+
+    return home + "/seaf_ext.log";
+}
+
+
+}
+
+void
+seaf_ext_log_start ()
+{
+    if (log_fp)
+        return;
+
+    std::string log_path = getLogPath();
+    if (!log_path.empty())
+        log_fp = fopen (log_path.c_str(), "a");
+
+    if (log_fp) {
+        seaf_ext_log ("\n----------------------------------\n"
+                      "log file initialized: 4.1.0 %s"
+                      "\n----------------------------------\n"
+                      , log_path.c_str());
+    } else {
+        fprintf (stderr, "[LOG] Can't init log file %s\n", log_path.c_str());
+    }
+}
+
+void
+seaf_ext_log_stop ()
+{
+    if (log_fp) {
+        fclose (log_fp);
+        log_fp = NULL;
+    }
+}
+
+void
+seaf_ext_log_aux (const char *format, ...)
+{
+    if (!log_fp)
+        seaf_ext_log_start();
+
+    if (log_fp) {
+        va_list params;
+        char buffer[1024];
+        size_t length = 0;
+
+        va_start(params, format);
+        length = vsnprintf(buffer, sizeof(buffer), format, params);
+        va_end(params);
+
+        /* Write the timestamp. */
+        time_t t;
+        struct tm *tm;
+        char buf[256];
+
+        t = time(NULL);
+        tm = localtime(&t);
+        strftime (buf, 256, "[%y/%m/%d %H:%M:%S] ", tm);
+
+        fputs (buf, log_fp);
+        if (fwrite(buffer, sizeof(char), length, log_fp) < length)
+            return;
+
+        fputc('\n', log_fp);
+        fflush(log_fp);
+    }
+}
diff --git a/extensions/log.h b/extensions/log.h
new file mode 100644 (file)
index 0000000..852650a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef SEAFILE_CLIENT_EXTENSION_LOG_H
+#define SEAFILE_CLIENT_EXTENSION_LOG_H
+
+void seaf_ext_log_start();
+void seaf_ext_log_stop();
+
+void seaf_ext_log_aux(const char *format, ...);
+
+#define seaf_ext_log(format, ... )                                  \
+    seaf_ext_log_aux("%s(line %d) %s: " format,                     \
+                     __FILE__, __LINE__, __func__, ##__VA_ARGS__)   \
+
+
+#endif  // SEAFILE_CLIENT_EXTENSION_LOG_H
diff --git a/extensions/normal.ico b/extensions/normal.ico
new file mode 100644 (file)
index 0000000..1467855
Binary files /dev/null and b/extensions/normal.ico differ
diff --git a/extensions/paused.ico b/extensions/paused.ico
new file mode 100644 (file)
index 0000000..559891f
Binary files /dev/null and b/extensions/paused.ico differ
diff --git a/extensions/readonly.ico b/extensions/readonly.ico
new file mode 100644 (file)
index 0000000..559891f
Binary files /dev/null and b/extensions/readonly.ico differ
diff --git a/extensions/seafile_shell_ext.def b/extensions/seafile_shell_ext.def
new file mode 100644 (file)
index 0000000..eee0a85
--- /dev/null
@@ -0,0 +1,5 @@
+LIBRARY seafile_shell_ext
+EXPORTS
+DllMain
+DllCanUnloadNow PRIVATE
+DllGetClassObject PRIVATE
diff --git a/extensions/seafile_shell_ext.rc b/extensions/seafile_shell_ext.rc
new file mode 100644 (file)
index 0000000..2a5f605
--- /dev/null
@@ -0,0 +1,6 @@
+1 ICON  DISCARDABLE "paused.ico"
+2 ICON  DISCARDABLE "normal.ico"
+3 ICON  DISCARDABLE "syncing.ico"
+4 ICON  DISCARDABLE "error.ico"
+5 ICON  DISCARDABLE "locked-by-me.ico"
+6 ICON  DISCARDABLE "locked-by-others.ico"
diff --git a/extensions/shell-ext.cpp b/extensions/shell-ext.cpp
new file mode 100644 (file)
index 0000000..f66809f
--- /dev/null
@@ -0,0 +1,195 @@
+// Initialize GUIDs (should be done only and at-least once per DLL/EXE)
+#include <initguid.h>
+#include "guids.h"
+
+#include "ext-common.h"
+#include "ext-utils.h"
+#include "commands.h"
+#include "log.h"
+#include "shell-ext.h"
+
+namespace utils = seafile::utils;
+
+namespace {
+
+const int kWorktreeCacheExpireMSecs = 3 * 1000;
+
+} // namespace
+
+std::unique_ptr<seafile::RepoInfoList> ShellExt::repos_cache_;
+uint64_t ShellExt::cache_ts_;
+
+// *********************** ShellExt *************************
+ShellExt::ShellExt(seafile::RepoInfo::Status status)
+  : main_menu_(0),
+    index_(0),
+    first_(0),
+    last_(0)
+{
+    m_cRef = 0L;
+    InterlockedIncrement(&g_cRefThisDll);
+
+    sub_menu_ = CreateMenu();
+    next_active_item_ = 0;
+    status_ = status;
+
+    // INITCOMMONCONTROLSEX used = {
+    //     sizeof(INITCOMMONCONTROLSEX),
+    //         ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES
+    // };
+    // InitCommonControlsEx(&used);
+}
+
+ShellExt::~ShellExt()
+{
+    InterlockedDecrement(&g_cRefThisDll);
+}
+
+STDMETHODIMP ShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
+{
+    if (ppv == 0)
+        return E_POINTER;
+
+    *ppv = NULL;
+
+    if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) {
+        *ppv = static_cast<LPSHELLEXTINIT>(this);
+    }
+    else if (IsEqualIID(riid, IID_IContextMenu)) {
+        *ppv = static_cast<LPCONTEXTMENU>(this);
+    }
+    else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier)) {
+        *ppv = static_cast<IShellIconOverlayIdentifier*>(this);
+    }
+    // else if (IsEqualIID(riid, IID_IContextMenu3))
+    // {
+    //     *ppv = static_cast<LPCONTEXTMENU3>(this);
+    // }
+    else
+    {
+        return E_NOINTERFACE;
+    }
+
+    AddRef();
+    return S_OK;
+}
+
+STDMETHODIMP_(ULONG) ShellExt::AddRef()
+{
+    return ++m_cRef;
+}
+
+STDMETHODIMP_(ULONG) ShellExt::Release()
+{
+    if (--m_cRef)
+        return m_cRef;
+
+    delete this;
+
+    return 0L;
+}
+
+bool ShellExt::getReposList(seafile::RepoInfoList *wts)
+{
+    seafile::utils::MutexLocker lock(&repos_cache_mutex_);
+
+    uint64_t now = utils::currentMSecsSinceEpoch();
+    if (repos_cache_ && now < cache_ts_ + kWorktreeCacheExpireMSecs) {
+        *wts = *(repos_cache_.get());
+        // seaf_ext_log("use cached repos list!");
+        return true;
+    }
+
+    // no cached worktree list, send request to seafile client
+    seafile::ListReposCommand cmd;
+    seafile::RepoInfoList repos;
+    if (!cmd.sendAndWait(&repos)) {
+        // seaf_ext_log("ListReposCommand returned false!");
+        return false;
+    }
+
+    cache_ts_ = utils::currentMSecsSinceEpoch();
+    repos_cache_.reset(new seafile::RepoInfoList(repos));
+
+    *wts = repos;
+    return true;
+}
+
+bool ShellExt::pathInRepo(const std::string& path,
+                          std::string *path_in_repo,
+                          seafile::RepoInfo *repo)
+{
+    seafile::RepoInfoList repos;
+    if (!getReposList(&repos)) {
+        return false;
+    }
+    std::string p = utils::normalizedPath(path);
+
+    for (size_t i = 0; i < repos.size(); i++) {
+        std::string wt = repos[i].worktree;
+        // seaf_ext_log ("work tree is %s, path is %s\n", wt.c_str(), p.c_str());
+        if (p.size() >= wt.size() && p.substr(0, wt.size()) == wt) {
+            if (p.size() > wt.size() && p[wt.size()] != '/') {
+                continue;
+            }
+            *path_in_repo = p.substr(wt.size(), p.size() - wt.size());
+            if (repo) {
+                *repo = repos[i];
+            }
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool ShellExt::isRepoTopDir(const std::string& path)
+{
+    seafile::RepoInfoList repos;
+    if (!getReposList(&repos)) {
+        return false;
+    }
+
+    std::string p = utils::normalizedPath(path);
+    for (size_t i = 0; i < repos.size(); i++) {
+        std::string wt = repos[i].worktree;
+        if (p == wt) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+seafile::RepoInfo ShellExt::getRepoInfoByPath(const std::string& path)
+{
+    seafile::RepoInfoList repos;
+    if (!getReposList(&repos)) {
+        return seafile::RepoInfo();
+    }
+
+    std::string p = utils::normalizedPath(path);
+    for (size_t i = 0; i < repos.size(); i++) {
+        std::string wt = repos[i].worktree;
+        if (p == wt) {
+            return repos[i];
+        }
+    }
+
+    return seafile::RepoInfo();
+}
+
+seafile::RepoInfo::Status
+ShellExt::getRepoFileStatus(const std::string& repo_id,
+                            const std::string& path_in_repo,
+                            bool isdir)
+{
+    // TODO: get the files under the same folder in a single command to reduce overhead
+    seafile::GetFileStatusCommand cmd(repo_id, path_in_repo, isdir);
+    seafile::RepoInfo::Status status;
+    if (!cmd.sendAndWait(&status)) {
+        return seafile::RepoInfo::NoStatus;
+    }
+
+    return status;
+}
diff --git a/extensions/shell-ext.h b/extensions/shell-ext.h
new file mode 100644 (file)
index 0000000..5737607
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef SEAFILE_EXT_SHELL_EXT_H
+#define SEAFILE_EXT_SHELL_EXT_H
+
+#include <string>
+#include <memory>
+#include <vector>
+#include "commands.h"
+#include "ext-utils.h"
+
+extern  volatile LONG       g_cRefThisDll;          // Reference count of this DLL.
+extern  HINSTANCE           g_hmodThisDll;          // Instance handle for this DLL
+extern  HINSTANCE           g_hResInst;
+
+struct SeafileMenuItem {
+    std::string text;           /* displayed in the menu */
+    std::string help;           /* displayed in the status bar */
+};
+
+class ShellExt : public IContextMenu3,
+                 IShellIconOverlayIdentifier,
+                 IShellExtInit
+{
+
+protected:
+    ULONG                           m_cRef;
+
+    // IContextMenu2 wrapper functions to catch exceptions and send crash reports
+    STDMETHODIMP    QueryContextMenu_Wrap(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
+    STDMETHODIMP    InvokeCommand_Wrap(LPCMINVOKECOMMANDINFO lpcmi);
+    STDMETHODIMP    GetCommandString_Wrap(UINT_PTR idCmd, UINT uFlags, UINT FAR *reserved, LPSTR pszName, UINT cchMax);
+    STDMETHODIMP    HandleMenuMsg_Wrap(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+    // IContextMenu3 wrapper functions to catch exceptions and send crash reports
+    STDMETHODIMP    HandleMenuMsg2_Wrap(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult);
+
+    // IShellExtInit wrapper functions to catch exceptions and send crash reports
+    STDMETHODIMP    Initialize_Wrap(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hKeyID);
+
+    seafile::RepoInfo::Status status_;
+
+public:
+    ShellExt(seafile::RepoInfo::Status status = seafile::RepoInfo::NoStatus);
+    virtual ~ShellExt();
+
+    // IUnknown members
+    STDMETHODIMP         QueryInterface(REFIID, LPVOID FAR *);
+    STDMETHODIMP_(ULONG) AddRef();
+    STDMETHODIMP_(ULONG) Release();
+
+    // IContextMenu2 members
+    STDMETHODIMP    QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
+    STDMETHODIMP    InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
+    STDMETHODIMP    GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT FAR *reserved, LPSTR pszName, UINT cchMax);
+    STDMETHODIMP    HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+    // IContextMenu3 members
+    STDMETHODIMP    HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult);
+
+    // IShellIconOverlayIdentifier members
+    STDMETHODIMP    GetOverlayInfo(LPWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags);
+    STDMETHODIMP    GetPriority(int *pPriority);
+    STDMETHODIMP    IsMemberOf(LPCWSTR pwszPath, DWORD dwAttrib);
+
+     // IShellExtInit methods
+    STDMETHODIMP    Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hKeyID);
+
+private:
+    enum MenuOp {
+        GetShareLink,
+        GetInternalLink,
+        LockFile,
+        UnlockFile,
+        ShareToUser,
+        ShareToGroup,
+        ShowHistory,
+    };
+
+    void buildSubMenu(const seafile::RepoInfo& repo,
+                      const std::string& path_in_repo);
+    MENUITEMINFO createMenuItem(const std::string& text);
+    bool insertMainMenu();
+    void insertSubMenuItem(const std::string& text, MenuOp op);
+    void tweakMenu(HMENU menu);
+
+    bool getReposList(seafile::RepoInfoList *wts);
+    bool pathInRepo(const std::string& path, std::string *path_in_repo, seafile::RepoInfo *repo=0);
+    bool isRepoTopDir(const std::string& path);
+    seafile::RepoInfo getRepoInfoByPath(const std::string& path);
+    seafile::RepoInfo::Status getRepoFileStatus(const std::string& repo_id,
+                                                const std::string& path_in_repo,
+                                                bool isdir);
+    /* the file/dir current clicked on */
+    std::string path_;
+
+    static std::unique_ptr<seafile::RepoInfoList> repos_cache_;
+    static uint64_t cache_ts_;
+    seafile::utils::Mutex repos_cache_mutex_;
+
+    /* The main menu */
+    HMENU main_menu_;
+    /* The popup seafile submenu */
+    HMENU sub_menu_;
+    UINT index_;
+    UINT first_;
+    UINT last_;
+    UINT next_active_item_;
+
+    std::vector<MenuOp> active_menu_items_;
+};
+
+#endif // SEAFILE_EXT_SHELL_EXT_H
diff --git a/extensions/syncing.ico b/extensions/syncing.ico
new file mode 100644 (file)
index 0000000..e2db381
Binary files /dev/null and b/extensions/syncing.ico differ
diff --git a/fsplugin/.clang-format b/fsplugin/.clang-format
new file mode 100644 (file)
index 0000000..258b755
--- /dev/null
@@ -0,0 +1,4 @@
+BasedOnStyle: LLVM
+Standard: Cpp11
+IndentWidth: 4
+TabWidth: 4
diff --git a/fsplugin/.tx/config b/fsplugin/.tx/config
new file mode 100644 (file)
index 0000000..e771ef9
--- /dev/null
@@ -0,0 +1,9 @@
+[main]
+host = https://www.transifex.com
+
+[seafile-client.finder-sync]
+file_filter = <lang>.lproj/Localizable.strings
+source_file = en.lproj/Localizable.strings
+source_lang = en
+type = STRINGS
+
diff --git a/fsplugin/CMakeLists.txt b/fsplugin/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c993f9c
--- /dev/null
@@ -0,0 +1,129 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11)
+
+PROJECT(seafile-fsplugin)
+SET(PROJECT_VERSION "1.0.0")
+
+IF (NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
+  SET(CMAKE_BUILD_TYPE Debug)
+ENDIF()
+
+SET(CODESIGN_CERTIFICATE "-" CACHE STRING "the certificate to sign code")
+
+MESSAGE(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
+
+IF (NOT APPLE)
+    MESSAGE(FATAL_ERROR "Support only on OS X")
+ENDIF()
+
+IF (NOT CMAKE_GENERATOR STREQUAL Xcode)
+    MESSAGE(FATAL_ERROR "Support only for Xcode generator")
+ENDIF()
+
+## Build with warnings
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wsign-compare -Wno-long-long -Wno-unused-parameter")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wsign-compare -Wno-long-long -Wno-unused-parameter -Woverloaded-virtual")
+
+## Find the dependencies
+
+FIND_LIBRARY(AppKit_LIBRARY AppKit)
+FIND_LIBRARY(FinderSync_LIBRARY FinderSync)
+FIND_LIBRARY(PlugInKit_LIBRARY PlugInKit
+  PATHS ${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks/)
+
+if (NOT PlugInKit_LIBRARY)
+  MESSAGE(FATAL_ERROR "PlugInKit not found")
+endif()
+
+ADD_DEFINITIONS(-fapplication-extension -fmodules)
+SET(CMAKE_EXE_LINKER_FLAGS "-fapplication-extension -e _NSExtensionMain -fobjc-arc -fobjc-link-runtime ${CMAKE_EXE_LINKER_FLAGS}")
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+SET(FSPLUGIN_SRC
+  ../src/utils/stl.cpp
+  ../src/utils/stl.h
+  FinderSync.mm
+  FinderSyncClient.mm
+  )
+
+## update en.lproj
+ADD_CUSTOM_TARGET(update-lproj
+  COMMAND genstrings -o en.lproj ${FSPLUGIN_SRC}
+  DEPENDS ${FSPLUGIN_SRC})
+
+ADD_EXECUTABLE(seafile-finder-sync MACOSX_BUNDLE
+  ${FSPLUGIN_SRC}
+)
+
+SET_TARGET_PROPERTIES(seafile-finder-sync PROPERTIES
+  OUTPUT_NAME "Seafile FinderSync"
+  MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist
+  XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "10.10"
+  XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks @executable_path/../../../../Frameworks"
+  XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES"
+  XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11"
+  XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++"
+  XCODE_ATTRIBUTE_DEVELOPMENT_LANGUAGE "English"
+  XCODE_ATTRIBUTE_LOCALIZED_RESOURCES_FOLDER_PATH "Seafile FinderSync.appex/English.lproj"
+  XCODE_ATTRIBUTE_INFOSTRINGS_PATH "Seafile FinderSync.appex/English.lproj/InfoPlist.strings"
+  XCODE_ATTRIBUTE_UNLOCALIZED_RESOURCES_FOLDER_PATH "Seafile FinderSync.appex"
+  )
+
+TARGET_LINK_LIBRARIES(seafile-finder-sync
+  ${FinderSync_LIBRARY}
+  ${PlugInKit_LIBRARY}
+  ${AppKit_LIBRARY}
+)
+
+### rename to Seafile Client.appex and copy related resource files
+
+SET(BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/Seafile FinderSync.app")
+SET(TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}/Seafile FinderSync.appex")
+
+ADD_CUSTOM_TARGET(clean_old_target
+  COMMAND ${CMAKE_COMMAND} -E remove -f ${TARGET_DIR}
+  )
+ADD_CUSTOM_TARGET(copy_fsplugin
+  COMMAND ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR} ${TARGET_DIR}
+  DEPENDS seafile-finder-sync clean_old_target
+  )
+
+ADD_CUSTOM_TARGET(create_resource_dir
+  COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET_DIR}/Contents/Resources
+  DEPENDS copy_fsplugin
+  )
+ADD_CUSTOM_TARGET(copy_resources_icns
+  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/../seafile.icns ${TARGET_DIR}/Contents/Resources/
+  COMMAND ${CMAKE_COMMAND} -E copy status-done.icns ${TARGET_DIR}/Contents/Resources/
+  COMMAND ${CMAKE_COMMAND} -E copy status-error.icns ${TARGET_DIR}/Contents/Resources/
+  COMMAND ${CMAKE_COMMAND} -E copy status-syncing.icns ${TARGET_DIR}/Contents/Resources/
+  COMMAND ${CMAKE_COMMAND} -E copy status-ignored.icns ${TARGET_DIR}/Contents/Resources/
+  COMMAND ${CMAKE_COMMAND} -E copy status-locked.icns ${TARGET_DIR}/Contents/Resources/
+  COMMAND ${CMAKE_COMMAND} -E copy status-locked-by-me.icns ${TARGET_DIR}/Contents/Resources/
+  DEPENDS create_resource_dir
+  )
+ADD_CUSTOM_TARGET(copy_resources_lproj
+  DEPENDS create_resource_dir)
+
+SET(FSPLUGIN_LANGS)
+file(GLOB FSPLUGIN_LPROJS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.lproj")
+
+FOREACH(LPROJ ${FSPLUGIN_LPROJS})
+  STRING(REGEX REPLACE "^.*/([a-z]+)\\.lproj/.*$" "\\1" _LANG ${LPROJ})
+  LIST(FIND FSPLUGIN_LANGS "${_LANG}" _INDEX)
+  IF(_INDEX EQUAL -1)
+    LIST(APPEND FSPLUGIN_LANGS ${_LANG})
+    ADD_CUSTOM_TARGET(copy_resources_lproj_${_LANG}
+    COMMAND cp -r ${_LANG} ${TARGET_DIR}/Contents/Resources/
+    DEPENDS create_resource_dir)
+    ADD_DEPENDENCIES(copy_resources_lproj copy_resources_lproj_${_LANG})
+  ENDIF(_INDEX EQUAL -1)
+ENDFOREACH()
+
+### codesign
+
+FIND_PROGRAM(CODESIGN codesign)
+
+ADD_CUSTOM_TARGET(codesign ALL
+  COMMAND ${CODESIGN} --force --sign ${CODESIGN_CERTIFICATE} --entitlements ${CMAKE_CURRENT_SOURCE_DIR}/seafile-fsplugin.entitlements ${TARGET_DIR}
+  DEPENDS copy_resources_icns copy_resources_lproj
+  )
diff --git a/fsplugin/FinderSync.h b/fsplugin/FinderSync.h
new file mode 100644 (file)
index 0000000..cd98164
--- /dev/null
@@ -0,0 +1,17 @@
+//
+//  FinderSync.h
+//  seafile-client-fsplugin
+//
+//  Created by Chilledheart on 1/10/15.
+//  Copyright (c) 2015 Haiwen. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import <FinderSync/FinderSync.h>
+
+@interface FinderSync : FIFinderSync
+- (void)updateWatchSet:(void *)ptr_to_new_repos;
+- (void)updateFileStatus:(const char *)repo_id
+                    path:(const char *)path
+                  status:(uint32_t)status;
+@end
diff --git a/fsplugin/FinderSync.mm b/fsplugin/FinderSync.mm
new file mode 100644 (file)
index 0000000..e1e13aa
--- /dev/null
@@ -0,0 +1,597 @@
+//
+//  FinderSync.m
+//  seafile-client-fsplugin
+//
+//  Created by Chilledheart on 1/10/15.
+//  Copyright (c) 2015 Haiwen. All rights reserved.
+//
+
+#import "FinderSync.h"
+#import "FinderSyncClient.h"
+#include <utility>
+#include <map>
+#include <unordered_map>
+#include <algorithm>
+
+#if !__has_feature(objc_arc)
+#error this file must be built with ARC support
+#endif
+
+@interface FinderSync ()
+
+@property(readwrite, nonatomic, strong) NSTimer *update_watch_set_timer_;
+@property(readwrite, nonatomic, strong) NSTimer *update_file_status_timer_;
+@property(readwrite, nonatomic, strong) dispatch_queue_t client_command_queue_;
+@end
+
+static const char *const kClientCommandQueueName =
+    "com.seafile.seafile-client.findersync.ClientCommandQueue";
+static const NSArray *const kBadgetIdentifiers = @[
+    // According to the document
+    // https://developer.apple.com/library/mac/documentation/FinderSync/Reference/FIFinderSyncController_Class/#//apple_ref/occ/instm/FIFinderSyncController/setBadgeIdentifier:forURL:
+    // Setting the identifier to an empty string (@"") removes the badge.
+    @"",            // none
+    @"syncing",      // syncing
+    @"error",        // error
+    @"",            // ignored
+    @"synced",       // synced
+    @"paused",       // readonly
+    @"paused",       // paused
+    @"locked",       // locked
+    @"locked_by_me", // locked by me
+];
+
+// Set up images for our badge identifiers. For demonstration purposes,
+static void initializeBadgeImages() {
+    // Set up images for our badge identifiers. For demonstration purposes,
+    // NONE,
+    // @""
+    // SYNCING,
+    [[FIFinderSyncController defaultController]
+             setBadgeImage:[NSImage imageNamed:@"status-syncing.icns"]
+                     label:NSLocalizedString(@"Syncing", @"Status Syncing")
+        forBadgeIdentifier:kBadgetIdentifiers[PathStatus::SYNC_STATUS_SYNCING]];
+    // ERROR,
+    [[FIFinderSyncController defaultController]
+             setBadgeImage:[NSImage imageNamed:@"status-error.icns"]
+                     label:NSLocalizedString(@"Error", @"Status Erorr")
+        forBadgeIdentifier:kBadgetIdentifiers[PathStatus::SYNC_STATUS_ERROR]];
+    // SYNCED,
+    [[FIFinderSyncController defaultController]
+             setBadgeImage:[NSImage imageNamed:@"status-done.icns"]
+                     label:NSLocalizedString(@"Finished", @"Status Finished")
+        forBadgeIdentifier:kBadgetIdentifiers[PathStatus::SYNC_STATUS_SYNCED]];
+    // PAUSED,
+    [[FIFinderSyncController defaultController]
+             setBadgeImage:[NSImage imageNamed:@"status-ignored.icns"]
+                     label:NSLocalizedString(@"Paused", @"Status Paused")
+        forBadgeIdentifier:kBadgetIdentifiers[PathStatus::SYNC_STATUS_PAUSED]];
+    // LOCKED,
+    [[FIFinderSyncController defaultController]
+             setBadgeImage:[NSImage imageNamed:@"status-locked.icns"]
+                     label:NSLocalizedString(@"Locked", @"Status Locked")
+        forBadgeIdentifier:kBadgetIdentifiers[PathStatus::SYNC_STATUS_LOCKED]];
+    // LOCKED_BY_ME,
+    [[FIFinderSyncController defaultController]
+             setBadgeImage:[NSImage imageNamed:@"status-locked-by-me.icns"]
+                     label:NSLocalizedString(@"Locked", @"Status LockedByMe")
+        forBadgeIdentifier:kBadgetIdentifiers
+                               [PathStatus::SYNC_STATUS_LOCKED_BY_ME]];
+}
+
+inline static void setBadgeIdentifierFor(NSURL *url, PathStatus status) {
+    [[FIFinderSyncController defaultController]
+        setBadgeIdentifier:kBadgetIdentifiers[status]
+                    forURL:url];
+}
+
+inline static void setBadgeIdentifierFor(const std::string &path,
+                                         PathStatus status) {
+    bool isDirectory = path.back() == '/';
+    std::string file = path;
+    if (isDirectory)
+        file.resize(file.size() - 1);
+    setBadgeIdentifierFor(
+        [NSURL fileURLWithPath:[NSString stringWithUTF8String:file.c_str()]
+                   isDirectory:isDirectory],
+        status);
+}
+
+inline static bool isUnderFolderDirectly(const std::string &path,
+                                         const std::string &dir) {
+    if (strncmp(dir.data(), path.data(), dir.size()) != 0) {
+        return false;
+    }
+    const char *pos = path.data() + dir.size();
+    const char *end = pos + path.size() - (dir.size());
+    if (end == pos)
+        return true;
+    // remove the trailing "/" in the end
+    if (*(end - 1) == '/')
+        --end;
+    while (pos != end)
+        if (*pos++ == '/')
+            return false;
+    return true;
+}
+
+inline static std::vector<LocalRepo>::const_iterator
+findRepo(const std::vector<LocalRepo> &repos, const std::string &repo_id) {
+    auto pos = repos.begin();
+    for (; pos != repos.end(); ++pos) {
+        if (repo_id == pos->repo_id)
+            break;
+    }
+    return pos;
+}
+
+inline static std::string getRelativePath(const std::string &path,
+                                          const std::string &prefix) {
+
+    std::string relative_path;
+    // remove the trailing "/" in the header
+    if (path.size() != prefix.size()) {
+        relative_path = std::string(path.data() + prefix.size() + 1,
+                                    path.size() - prefix.size() - 1);
+    }
+    return relative_path;
+}
+
+inline static bool isContainsPrefix(const std::string &path,
+                                    const std::string &prefix) {
+    if (prefix.size() > path.size())
+        return false;
+    if (0 != strncmp(prefix.data(), path.data(), prefix.size()))
+        return false;
+    if (prefix.size() < path.size() && path[prefix.size()] != '/')
+        return false;
+    return true;
+}
+
+inline static std::vector<LocalRepo>::const_iterator
+findRepoContainPath(const std::vector<LocalRepo> &repos,
+                    const std::string &path) {
+    for (auto repo = repos.begin(); repo != repos.end(); ++repo) {
+        if (isContainsPrefix(path, repo->worktree))
+            return repo;
+    }
+    return repos.end();
+}
+
+inline static void cleanEntireDirectoryStatus(
+    std::unordered_map<std::string, PathStatus> *file_status,
+    const std::string &dir) {
+    for (auto file = file_status->begin(); file != file_status->end();) {
+        auto pos = file++;
+        if (!isContainsPrefix(pos->first, dir))
+            continue;
+        setBadgeIdentifierFor(pos->first, PathStatus::SYNC_STATUS_NONE);
+        file_status->erase(pos);
+    }
+}
+
+inline static void
+cleanDirectoryStatus(std::unordered_map<std::string, PathStatus> *file_status,
+                     const std::string &dir) {
+    for (auto file = file_status->begin(); file != file_status->end();) {
+        auto pos = file++;
+        if (!isUnderFolderDirectly(pos->first, dir))
+            continue;
+        file_status->erase(pos);
+    }
+}
+
+static void
+cleanFileStatus(std::unordered_map<std::string, PathStatus> *file_status,
+                const std::vector<LocalRepo> &watch_set,
+                const std::vector<LocalRepo> &new_watch_set) {
+    for (const auto &repo : watch_set) {
+        bool found = false;
+        for (const auto &new_repo : new_watch_set) {
+            if (repo == new_repo) {
+                found = true;
+                break;
+            }
+        }
+        // cleanup old
+        if (!found) {
+            // clean up root
+            setBadgeIdentifierFor(repo.worktree, PathStatus::SYNC_STATUS_NONE);
+
+            // clean up leafs
+            cleanEntireDirectoryStatus(file_status, repo.worktree);
+        }
+    }
+    for (const auto &new_repo : new_watch_set) {
+        bool found = false;
+        for (const auto &repo : watch_set) {
+            if (repo == new_repo) {
+                found = true;
+                break;
+            }
+        }
+        // add new if necessary
+        if (!found)
+            file_status->emplace(new_repo.worktree + "/",
+                                 PathStatus::SYNC_STATUS_NONE);
+    }
+}
+
+static std::vector<LocalRepo> watched_repos_;
+static std::unordered_map<std::string, PathStatus> file_status_;
+static FinderSyncClient *client_ = nullptr;
+static constexpr double kGetWatchSetInterval = 5.0;   // seconds
+static constexpr double kGetFileStatusInterval = 2.0; // seconds
+
+@implementation FinderSync
+
+- (instancetype)init {
+    self = [super init];
+
+#ifdef NDEBUG
+    NSLog(@"%s launched from %@ ; compiled at %s", __PRETTY_FUNCTION__,
+          [[NSBundle mainBundle] bundlePath], __DATE__);
+#else
+    NSLog(@"%s launched from %@ ; compiled at %s %s", __PRETTY_FUNCTION__,
+          [[NSBundle mainBundle] bundlePath], __TIME__, __DATE__);
+#endif
+
+    // Set up client queue
+    self.client_command_queue_ =
+        dispatch_queue_create(kClientCommandQueueName, DISPATCH_QUEUE_SERIAL);
+    // Set up client
+    client_ = new FinderSyncClient(self);
+    self.update_watch_set_timer_ =
+        [NSTimer scheduledTimerWithTimeInterval:kGetWatchSetInterval
+                                         target:self
+                                       selector:@selector(requestUpdateWatchSet)
+                                       userInfo:nil
+                                        repeats:YES];
+
+    self.update_file_status_timer_ = [NSTimer
+        scheduledTimerWithTimeInterval:kGetFileStatusInterval
+                                target:self
+                              selector:@selector(requestUpdateFileStatus)
+                              userInfo:nil
+                               repeats:YES];
+
+    [FIFinderSyncController defaultController].directoryURLs = nil;
+
+    return self;
+}
+
+- (void)dealloc {
+    delete client_;
+    self.client_command_queue_ = nil;
+}
+
+#pragma mark - Primary Finder Sync protocol methods
+
+- (void)beginObservingDirectoryAtURL:(NSURL *)url {
+    // convert NFD to NFC
+    std::string absolute_path =
+        url.path.precomposedStringWithCanonicalMapping.UTF8String;
+
+    // find where we have it
+    auto repo = findRepoContainPath(watched_repos_, absolute_path);
+    if (repo == watched_repos_.end())
+        return;
+
+    if (absolute_path.back() != '/')
+        absolute_path += "/";
+
+    file_status_.emplace(absolute_path, PathStatus::SYNC_STATUS_NONE);
+}
+
+- (void)endObservingDirectoryAtURL:(NSURL *)url {
+    // convert NFD to NFC
+    std::string absolute_path =
+        url.path.precomposedStringWithCanonicalMapping.UTF8String;
+
+    if (absolute_path.back() != '/')
+        absolute_path += "/";
+
+    cleanDirectoryStatus(&file_status_, absolute_path);
+}
+
+- (void)requestBadgeIdentifierForURL:(NSURL *)url {
+    // convert NFD to NFC
+    std::string file_path =
+        url.path.precomposedStringWithCanonicalMapping.UTF8String;
+
+    // find where we have it
+    auto repo = findRepoContainPath(watched_repos_, file_path);
+    if (repo == watched_repos_.end())
+        return;
+
+    NSNumber *isDirectory;
+    if ([url getResourceValue:&isDirectory
+                       forKey:NSURLIsDirectoryKey
+                        error:nil] &&
+        [isDirectory boolValue]) {
+        file_path += "/";
+    }
+
+    std::string repo_id = repo->repo_id;
+    std::string relative_path = getRelativePath(file_path, repo->worktree);
+    if (relative_path.empty())
+        return;
+
+    file_status_.emplace(file_path, PathStatus::SYNC_STATUS_NONE);
+    setBadgeIdentifierFor(file_path, PathStatus::SYNC_STATUS_NONE);
+    dispatch_async(self.client_command_queue_, ^{
+      client_->doGetFileStatus(repo_id.c_str(), relative_path.c_str());
+    });
+}
+
+#pragma mark - Menu and toolbar item support
+
+#if 0
+- (NSString *)toolbarItemName {
+  return @"Seafile FinderSync";
+}
+
+- (NSString *)toolbarItemToolTip {
+  return @"Seafile FinderSync: Click the toolbar item for a menu.";
+}
+
+- (NSImage *)toolbarItemImage {
+  return [NSImage imageNamed:NSImageNameFolder];
+}
+#endif
+
+- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu {
+    if (whichMenu != FIMenuKindContextualMenuForItems &&
+        whichMenu != FIMenuKindContextualMenuForContainer)
+        return nil;
+
+    // Produce a menu for the extension.
+    NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
+    NSMenuItem *shareLinkItem =
+        [menu addItemWithTitle:NSLocalizedString(@"Get Seafile Download Link",
+                                                 @"Get Seafile Download Link")
+                        action:@selector(shareLinkAction:)
+                 keyEquivalent:@""];
+    NSImage *seafileImage = [NSImage imageNamed:@"seafile.icns"];
+    [shareLinkItem setImage:seafileImage];
+
+    NSArray *items =
+        [[FIFinderSyncController defaultController] selectedItemURLs];
+    if (![items count])
+        return nil;
+    NSURL *item = items.firstObject;
+    std::string file_path =
+        item.path.precomposedStringWithCanonicalMapping.UTF8String;
+
+    auto repo = findRepoContainPath(watched_repos_, file_path);
+    if (repo != watched_repos_.end() && repo->internal_link_supported) {
+        NSMenuItem *internalLinkItem =
+            [menu addItemWithTitle:NSLocalizedString(@"Get Seafile Internal Link",
+                                                     @"Get Seafile Internal Link")
+                            action:@selector(internalLinkAction:)
+                     keyEquivalent:@""];
+        [internalLinkItem setImage:seafileImage];
+    }
+
+    // add a menu item for lockFile
+
+    NSNumber *isDirectory;
+    bool is_dir = [item getResourceValue:&isDirectory
+                                  forKey:NSURLIsDirectoryKey
+                                   error:nil] &&
+                  [isDirectory boolValue];
+
+    // we don't have a lock-file menuitem for folders
+    // early return
+    if (is_dir)
+        return menu;
+
+    // find where we have it
+    auto file = file_status_.find(is_dir ? file_path + "/" : file_path);
+    if (file != file_status_.end()) {
+        NSString *lockFileTitle;
+        if (file->second != PathStatus::SYNC_STATUS_LOCKED) {
+            if (file->second == PathStatus::SYNC_STATUS_LOCKED_BY_ME) {
+                lockFileTitle =
+                    NSLocalizedString(@"Unlock This File", @"Unlock This File");
+            } else {
+                lockFileTitle = NSLocalizedString(@"Lock This File", @"Lock This File");
+            }
+        } else {
+            lockFileTitle = NSLocalizedString(@"Lock This File", @"Lock This File");
+        }
+
+        NSMenuItem *lockFileItem = [menu addItemWithTitle:lockFileTitle
+                                                   action:@selector(lockFileAction:)
+                                            keyEquivalent:@""];
+
+        [lockFileItem setImage:seafileImage];
+
+        if (file->second == PathStatus::SYNC_STATUS_LOCKED || file->second == PathStatus::SYNC_STATUS_READONLY)
+            [lockFileItem setEnabled:FALSE];
+    }
+
+    // NSString *showHistoryTitle;
+    NSMenuItem *showHistoryItem =
+        [menu addItemWithTitle:NSLocalizedString(@"View File History",
+                                                 @"View File History")
+                        action:@selector(showHistoryAction:)
+                 keyEquivalent:@""];
+    [showHistoryItem setImage:seafileImage];
+
+    return menu;
+}
+
+- (IBAction)shareLinkAction:(id)sender {
+    NSArray *items =
+        [[FIFinderSyncController defaultController] selectedItemURLs];
+    if (![items count])
+        return;
+    NSURL *item = items.firstObject;
+
+    // do it in another thread
+    std::string path =
+        item.path.precomposedStringWithCanonicalMapping.UTF8String;
+    NSNumber *isDirectory;
+    if ([item getResourceValue:&isDirectory
+                        forKey:NSURLIsDirectoryKey
+                         error:nil] &&
+        [isDirectory boolValue])
+        path += "/";
+
+    dispatch_async(self.client_command_queue_, ^{
+      client_->doSendCommandWithPath(FinderSyncClient::DoShareLink,
+                                     path.c_str());
+    });
+}
+
+- (IBAction)internalLinkAction:(id)sender {
+    NSArray *items =
+        [[FIFinderSyncController defaultController] selectedItemURLs];
+    if (![items count])
+        return;
+    NSURL *item = items.firstObject;
+
+    // do it in another thread
+    std::string path =
+        item.path.precomposedStringWithCanonicalMapping.UTF8String;
+    NSNumber *isDirectory;
+    if ([item getResourceValue:&isDirectory
+                        forKey:NSURLIsDirectoryKey
+                         error:nil] &&
+        [isDirectory boolValue])
+        path += "/";
+
+    dispatch_async(self.client_command_queue_, ^{
+      client_->doSendCommandWithPath(FinderSyncClient::DoInternalLink,
+                                     path.c_str());
+    });
+}
+
+- (IBAction)lockFileAction:(id)sender {
+    NSArray *items =
+        [[FIFinderSyncController defaultController] selectedItemURLs];
+    if (![items count])
+        return;
+    NSURL *item = items.firstObject;
+
+    std::string path =
+        item.path.precomposedStringWithCanonicalMapping.UTF8String;
+    // find where we have it
+    auto file = file_status_.find(path);
+    if (file == file_status_.end())
+        return;
+    if (file->second == PathStatus::SYNC_STATUS_LOCKED)
+        return;
+
+    FinderSyncClient::CommandType command;
+    if (file->second == PathStatus::SYNC_STATUS_LOCKED_BY_ME)
+        command = FinderSyncClient::DoUnlockFile;
+    else
+        command = FinderSyncClient::DoLockFile;
+
+    // we cannot lock a directory
+    NSNumber *isDirectory;
+    if ([item getResourceValue:&isDirectory
+                        forKey:NSURLIsDirectoryKey
+                         error:nil] &&
+        [isDirectory boolValue])
+        return;
+
+    // do it in another thread
+    dispatch_async(self.client_command_queue_, ^{
+      client_->doSendCommandWithPath(command, path.c_str());
+    });
+}
+
+- (IBAction)showHistoryAction:(id)sender {
+    NSArray *items =
+        [[FIFinderSyncController defaultController] selectedItemURLs];
+    if (![items count])
+        return;
+    NSURL *item = items.firstObject;
+
+    // do it in another thread
+    std::string path =
+        item.path.precomposedStringWithCanonicalMapping.UTF8String;
+    dispatch_async(self.client_command_queue_, ^{
+      client_->doSendCommandWithPath(FinderSyncClient::DoShowFileHistory,
+                                     path.c_str());
+    });
+}
+
+
+- (void)requestUpdateWatchSet {
+    // do it in another thread
+    dispatch_async(self.client_command_queue_, ^{
+      client_->getWatchSet();
+    });
+}
+
+- (void)updateWatchSet:(void *)ptr_to_new_watched_repos {
+    std::vector<LocalRepo> new_watched_repos;
+    if (ptr_to_new_watched_repos)
+        new_watched_repos = std::move(
+            *static_cast<std::vector<LocalRepo> *>(ptr_to_new_watched_repos));
+
+    cleanFileStatus(&file_status_, watched_repos_, new_watched_repos);
+
+    // overwrite the old watch set
+    watched_repos_ = std::move(new_watched_repos);
+
+    // update FIFinderSyncController's directory URLs
+    NSMutableArray *array =
+        [NSMutableArray arrayWithCapacity:watched_repos_.size()];
+    for (const LocalRepo &repo : watched_repos_) {
+        NSString *path = [NSString stringWithUTF8String:repo.worktree.c_str()];
+        [array addObject:[NSURL fileURLWithPath:path isDirectory:YES]];
+    }
+
+    [FIFinderSyncController defaultController].directoryURLs =
+        [NSSet setWithArray:array];
+
+    // initialize the badge images
+    static bool initialized = false;
+    if (!initialized) {
+        initialized = true;
+        initializeBadgeImages();
+    }
+}
+
+- (void)requestUpdateFileStatus {
+    for (const auto &pair : file_status_) {
+        auto repo = findRepoContainPath(watched_repos_, pair.first);
+        if (repo == watched_repos_.end()) /* erase it ?*/
+            continue;
+
+        std::string relative_path = getRelativePath(pair.first, repo->worktree);
+        if (relative_path.empty())
+            relative_path = "/";
+        std::string repo_id = repo->repo_id;
+        dispatch_async(self.client_command_queue_, ^{
+          client_->doGetFileStatus(repo_id.c_str(), relative_path.c_str());
+        });
+    }
+}
+
+- (void)updateFileStatus:(const char *)repo_id
+                    path:(const char *)path
+                  status:(uint32_t)status {
+    auto repo = findRepo(watched_repos_, repo_id);
+    if (repo == watched_repos_.end())
+        return;
+
+    std::string absolute_path =
+        repo->worktree + (*path == '/' ? "" : "/") + path;
+
+    // if the path is erased, ignore it!
+    auto file = file_status_.find(absolute_path);
+    if (file == file_status_.end())
+        return;
+
+    // always set up, avoid some bugs
+    file->second = static_cast<PathStatus>(status);
+    setBadgeIdentifierFor(absolute_path, static_cast<PathStatus>(status));
+}
+
+@end
diff --git a/fsplugin/FinderSyncClient.h b/fsplugin/FinderSyncClient.h
new file mode 100644 (file)
index 0000000..5a5672f
--- /dev/null
@@ -0,0 +1,88 @@
+//
+//  FinderSyncClient.h
+//  seafile-client-fsplugin
+//
+//  Created by Chilledheart on 1/10/15.
+//  Copyright (c) 2015 Haiwen. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#include <thread>
+#include <mutex>
+
+#include <vector>
+#include <string>
+#include "FinderSync.h"
+
+enum PathStatus : uint32_t {
+    SYNC_STATUS_NONE = 0,
+    SYNC_STATUS_SYNCING,
+    SYNC_STATUS_ERROR,
+    SYNC_STATUS_IGNORED,
+    SYNC_STATUS_SYNCED,
+    SYNC_STATUS_READONLY,
+    SYNC_STATUS_PAUSED,
+    SYNC_STATUS_LOCKED,
+    SYNC_STATUS_LOCKED_BY_ME,
+    MAX_SYNC_STATUS,
+};
+
+struct LocalRepo {
+    LocalRepo() = default;
+    LocalRepo(const LocalRepo &) = delete;
+    LocalRepo &operator=(const LocalRepo &) = delete;
+
+    LocalRepo(LocalRepo &&) = default;
+    LocalRepo &operator=(LocalRepo &&) = default;
+    enum SyncState : uint8_t {
+        SYNC_STATE_DISABLED = 0,
+        SYNC_STATE_WAITING = 1,
+        SYNC_STATE_INIT = 2,
+        SYNC_STATE_ING = 3,
+        SYNC_STATE_DONE = 4,
+        SYNC_STATE_ERROR = 5,
+        SYNC_STATE_UNKNOWN = 6,
+        SYNC_STATE_UNSET = 7,
+        MAX_SYNC_STATE,
+    };
+    LocalRepo(std::string &&r, std::string &&w, SyncState s, bool _internal_link_supported)
+        : repo_id(std::move(r)), worktree(std::move(w)), status(s), internal_link_supported(_internal_link_supported) {}
+    LocalRepo(const std::string &r, const std::string &w, SyncState s, bool _internal_link_supported)
+        : repo_id(r), worktree(w), status(s), internal_link_supported(_internal_link_supported) {}
+    std::string repo_id;
+    std::string worktree;
+    SyncState status;
+    bool internal_link_supported;
+    friend bool operator==(const LocalRepo &lhs, const LocalRepo &rhs) {
+        return lhs.repo_id == rhs.repo_id;
+    }
+    friend bool operator!=(const LocalRepo &lhs, const LocalRepo &rhs) {
+        return !(lhs == rhs);
+    }
+};
+
+class FinderSyncClient {
+  public:
+    enum CommandType : uint32_t {
+        GetWatchSet = 0,
+        DoShareLink = 1,
+        DoGetFileStatus = 2,
+        DoInternalLink = 3,
+        DoLockFile = 4,
+        DoUnlockFile = 5,
+        DoShowFileHistory = 6,
+    };
+
+    FinderSyncClient(FinderSync *parent);
+    ~FinderSyncClient();
+    void getWatchSet();
+    void doSendCommandWithPath(CommandType command, const char *fileName);
+    void doGetFileStatus(const char *repo, const char *fileName);
+
+  private:
+    bool connect();
+    void connectionBecomeInvalid();
+    FinderSync __weak *parent_;
+    mach_port_t local_port_;
+    mach_port_t remote_port_;
+};
diff --git a/fsplugin/FinderSyncClient.mm b/fsplugin/FinderSyncClient.mm
new file mode 100644 (file)
index 0000000..733c1eb
--- /dev/null
@@ -0,0 +1,382 @@
+//
+//  FinderSyncClient.m
+//  seafile-client-fsplugin
+//
+//  Created by Chilledheart on 1/10/15.
+//  Copyright (c) 2015 Haiwen. All rights reserved.
+//
+
+#import "FinderSyncClient.h"
+#include <cstdint>
+#include <sstream>
+#include <iostream>
+#include <string>
+#include <servers/bootstrap.h>
+#include "../src/utils/stl.h"
+
+#if !__has_feature(objc_arc)
+#error this file must be built with ARC support
+#endif
+
+static NSString *const kFinderSyncMachPort =
+    @"com.seafile.seafile-client.findersync.machport";
+
+static constexpr int kPathMaxSize = 1024;
+static constexpr uint32_t kFinderSyncProtocolVersion = 0x00000004;
+static volatile int32_t message_id_ =
+    100; // we start from 100, the number below than 100 is reserved
+
+typedef std::vector<std::string> stringlist;
+
+stringlist split_string(const std::string& v, char delim) {
+    using namespace std;
+    stringlist strings;
+    istringstream ss(v);
+    string s;
+    while (getline(ss, s, delim)) {
+        strings.push_back(s);
+    }
+    return strings;
+}
+
+//
+// MachPort Message
+// - mach_msg_header_t command
+// - uint32_t version
+// - uint32_t command
+// - body
+// - mach_msg_trailer_t trailer (for rcv only)
+//
+//
+
+// buffer
+// <-char[36]-><----- char? ------------>1   1      1
+// <-repo_id--><---- [worktree name] --->0<[status]>0
+static std::vector<LocalRepo> *deserializeWatchSet(const char *buffer,
+                                                   uint32_t size) {
+    std::vector<LocalRepo> *repos = new std::vector<LocalRepo>();
+    const char *const end = buffer + size - 1;
+    const char *pos;
+    while (buffer != end) {
+        unsigned worktree_size;
+        uint8_t status;
+        const char *repo_id = buffer;
+        buffer += 36;
+        pos = buffer;
+
+        while (*pos != '\0' && pos != end)
+            ++pos;
+        worktree_size = pos - buffer;
+        pos += 2;
+        if (pos > end || *pos != '\0')
+            break;
+
+        status = *(pos - 1);
+        if (status >= LocalRepo::MAX_SYNC_STATE) {
+            status = LocalRepo::SYNC_STATE_UNSET;
+        }
+        bool internal_link_supported = false;
+        std::string worktree = std::string(buffer, worktree_size);
+        // NSLog(@"full line = %s", worktree.c_str());
+        stringlist parts = split_string(worktree, '\t');
+        if (parts.size() > 1) {
+            worktree = parts[0];
+            // NSLog(@"worktree = %s", worktree.c_str());
+            internal_link_supported = parts[1] == "internal-link-supported";
+        }
+
+        repos->emplace_back(std::string(repo_id, 36),
+                            worktree,
+                            static_cast<LocalRepo::SyncState>(status),
+                            internal_link_supported);
+        buffer = ++pos;
+    }
+    return repos;
+}
+
+struct mach_msg_command_send_t {
+    mach_msg_header_t header;
+    uint32_t version;
+    uint32_t command;
+    // used only in DoShareLink
+    char repo[36];
+    char body[kPathMaxSize];
+};
+
+struct mach_msg_file_status_rcv_t {
+    mach_msg_header_t header;
+    uint32_t version;
+    uint32_t command;
+    uint32_t status;
+    mach_msg_trailer_t trailer;
+};
+
+FinderSyncClient::FinderSyncClient(FinderSync *parent)
+    : parent_(parent), local_port_(MACH_PORT_NULL),
+      remote_port_(MACH_PORT_NULL) {}
+
+FinderSyncClient::~FinderSyncClient() {
+    if (local_port_) {
+        mach_port_mod_refs(mach_task_self(), local_port_,
+                           MACH_PORT_RIGHT_RECEIVE, -1);
+    }
+    if (remote_port_) {
+        NSLog(@"disconnecting from Seafile Client");
+        mach_port_deallocate(mach_task_self(), remote_port_);
+    }
+}
+
+void FinderSyncClient::connectionBecomeInvalid() {
+    /* clean up old connection stage! */
+    if (local_port_) {
+        mach_port_mod_refs(mach_task_self(), local_port_,
+                           MACH_PORT_RIGHT_RECEIVE, -1);
+        local_port_ = MACH_PORT_NULL;
+    }
+    if (remote_port_) {
+        NSLog(@"lost connection with Seafile Client");
+        mach_port_deallocate(mach_task_self(), remote_port_);
+        dispatch_async(dispatch_get_main_queue(), ^{
+          [parent_ updateWatchSet:nil];
+        });
+        remote_port_ = MACH_PORT_NULL;
+    }
+}
+
+bool FinderSyncClient::connect() {
+    if (!local_port_) {
+        // Create a local port.
+        kern_return_t kr = mach_port_allocate(
+            mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &local_port_);
+        if (kr != KERN_SUCCESS) {
+            NSLog(@"unable to create connection");
+            return false;
+        }
+    }
+
+    if (!remote_port_) {
+        // connect to the mach_port
+        kern_return_t kr = bootstrap_look_up(
+            bootstrap_port,
+            [kFinderSyncMachPort cStringUsingEncoding:NSASCIIStringEncoding],
+            &remote_port_);
+
+        if (kr != KERN_SUCCESS) {
+            return false;
+        }
+        NSLog(@"connected to Seafile Client");
+    }
+
+    return true;
+}
+
+void FinderSyncClient::getWatchSet() {
+    if ([NSThread isMainThread]) {
+        NSLog(@"%s isn't supported to be called from main thread",
+              __PRETTY_FUNCTION__);
+        return;
+    }
+    if (!connect())
+        return;
+    mach_msg_command_send_t msg;
+    const int32_t recv_msgh_id = OSAtomicAdd32(2, &message_id_) - 1;
+    bzero(&msg, sizeof(mach_msg_header_t));
+    msg.header.msgh_id = recv_msgh_id - 1;
+    msg.header.msgh_local_port = local_port_;
+    msg.header.msgh_remote_port = remote_port_;
+    msg.header.msgh_size = sizeof(msg);
+    msg.header.msgh_bits =
+        MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+    msg.version = kFinderSyncProtocolVersion;
+    msg.command = GetWatchSet;
+    // send a message and wait for the reply
+    kern_return_t kr = mach_msg(&msg.header,                       /* header*/
+                                MACH_SEND_MSG | MACH_SEND_TIMEOUT, /*option*/
+                                sizeof(msg),                       /*send size*/
+                                0,               /*receive size*/
+                                local_port_,     /*receive port*/
+                                100,             /*timeout, in milliseconds*/
+                                MACH_PORT_NULL); /*no notification*/
+    if (kr != MACH_MSG_SUCCESS) {
+        if (kr == MACH_SEND_INVALID_DEST) {
+            connectionBecomeInvalid();
+            return;
+        }
+        NSLog(@"failed to send request to Seafile Client");
+        NSLog(@"mach error %s", mach_error_string(kr));
+        connectionBecomeInvalid();
+        return;
+    }
+    mach_msg_destroy(&msg.header);
+
+    utils::BufferArray recv_msg;
+    recv_msg.resize(4096);
+    mach_msg_header_t *recv_msg_header =
+        reinterpret_cast<mach_msg_header_t *>(recv_msg.data());
+    bzero(recv_msg.data(), sizeof(mach_msg_header_t));
+    recv_msg_header->msgh_local_port = local_port_;
+    recv_msg_header->msgh_remote_port = remote_port_;
+    // recv_msg.header.msgh_size = sizeof(recv_msg);
+    // receive the reply
+    kr = mach_msg(recv_msg_header,                                  /* header*/
+                  MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_LARGE, /*option*/
+                  0,               /*send size*/
+                  recv_msg.size(), /*receive size*/
+                  local_port_,     /*receive port*/
+                  100,             /*timeout, in milliseconds*/
+                  MACH_PORT_NULL); /*no notification*/
+    // retry
+    if (kr == MACH_RCV_TOO_LARGE) {
+        recv_msg.resize(recv_msg_header->msgh_size +
+                        sizeof(mach_msg_trailer_t));
+        recv_msg_header =
+            reinterpret_cast<mach_msg_header_t *>(recv_msg.data());
+
+        kr = mach_msg(recv_msg_header,                 /* header*/
+                      MACH_RCV_MSG | MACH_RCV_TIMEOUT, /*option*/
+                      0,                               /*send size*/
+                      recv_msg.size(),                 /*receive size*/
+                      local_port_,                     /*receive port*/
+                      100,             /*timeout, in milliseconds*/
+                      MACH_PORT_NULL); /*no notification*/
+    }
+    if (kr != MACH_MSG_SUCCESS) {
+        NSLog(@"failed to receive Seafile Client's reply");
+        NSLog(@"mach error %s", mach_error_string(kr));
+        connectionBecomeInvalid();
+        return;
+    }
+    if (recv_msg_header->msgh_id != recv_msgh_id) {
+        NSLog(@"mach error unmatched message id %d, expected %d",
+              recv_msg_header->msgh_id, recv_msgh_id);
+        connectionBecomeInvalid();
+        return;
+    }
+    const char *body = recv_msg.data() + sizeof(mach_msg_header_t);
+    uint32_t body_size =
+        (recv_msg_header->msgh_size - sizeof(mach_msg_header_t));
+    std::vector<LocalRepo> *repos = deserializeWatchSet(body, body_size);
+    dispatch_async(dispatch_get_main_queue(), ^{
+      [parent_ updateWatchSet:repos];
+      delete repos;
+    });
+    mach_msg_destroy(recv_msg_header);
+}
+
+void FinderSyncClient::doSendCommandWithPath(CommandType command,
+                                             const char *fileName) {
+    if ([NSThread isMainThread]) {
+        NSLog(@"%s isn't supported to be called from main thread",
+              __PRETTY_FUNCTION__);
+        return;
+    }
+    if (!connect())
+        return;
+    mach_msg_command_send_t msg;
+    bzero(&msg, sizeof(msg));
+    msg.header.msgh_id = OSAtomicIncrement32(&message_id_) - 1;
+    msg.header.msgh_local_port = MACH_PORT_NULL;
+    msg.header.msgh_remote_port = remote_port_;
+    msg.header.msgh_size = sizeof(msg);
+    msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
+    strncpy(msg.body, fileName, kPathMaxSize);
+    msg.version = kFinderSyncProtocolVersion;
+    msg.command = command;
+    // send a message only
+    kern_return_t kr = mach_msg_send(&msg.header);
+    if (kr != MACH_MSG_SUCCESS) {
+        if (kr == MACH_SEND_INVALID_DEST) {
+            connectionBecomeInvalid();
+            return;
+        }
+        NSLog(@"failed to send sharing link request for %s", fileName);
+        NSLog(@"mach error %s from msg id %d", mach_error_string(kr),
+              msg.header.msgh_id);
+        connectionBecomeInvalid();
+        return;
+    }
+    mach_msg_destroy(&msg.header);
+}
+
+void FinderSyncClient::doGetFileStatus(const char *repo, const char *fileName) {
+    if ([NSThread isMainThread]) {
+        NSLog(@"%s isn't supported to be called from main thread",
+              __PRETTY_FUNCTION__);
+        return;
+    }
+    if (!connect())
+        return;
+    mach_msg_command_send_t msg;
+    const int32_t recv_msgh_id = OSAtomicAdd32(2, &message_id_) - 1;
+    bzero(&msg, sizeof(mach_msg_header_t));
+    msg.header.msgh_id = recv_msgh_id - 1;
+    msg.header.msgh_local_port = local_port_;
+    msg.header.msgh_remote_port = remote_port_;
+    msg.header.msgh_size = sizeof(msg);
+    msg.header.msgh_bits =
+        MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+    strncpy(msg.repo, repo, 36);
+    strncpy(msg.body, fileName, kPathMaxSize);
+    msg.version = kFinderSyncProtocolVersion;
+    msg.command = DoGetFileStatus;
+    // send a message and wait for the reply
+    kern_return_t kr = mach_msg(&msg.header,                       /* header*/
+                                MACH_SEND_MSG | MACH_SEND_TIMEOUT, /*option*/
+                                sizeof(msg),                       /*send size*/
+                                0,               /*receive size*/
+                                local_port_,     /*receive port*/
+                                100,             /*timeout, in milliseconds*/
+                                MACH_PORT_NULL); /*no notification*/
+    if (kr != MACH_MSG_SUCCESS) {
+        if (kr == MACH_SEND_INVALID_DEST) {
+            connectionBecomeInvalid();
+            return;
+        }
+        NSLog(@"failed to send request to Seafile Client");
+        NSLog(@"mach error %s", mach_error_string(kr));
+        connectionBecomeInvalid();
+        return;
+    }
+    mach_msg_destroy(&msg.header);
+
+    mach_msg_file_status_rcv_t recv_msg;
+    mach_msg_header_t *recv_msg_header =
+        reinterpret_cast<mach_msg_header_t *>(&recv_msg);
+    bzero(&recv_msg, sizeof(mach_msg_header_t));
+    recv_msg_header->msgh_local_port = local_port_;
+    recv_msg_header->msgh_remote_port = remote_port_;
+    // recv_msg.header.msgh_size = sizeof(recv_msg);
+    // receive the reply
+    kr = mach_msg(recv_msg_header,                    /* header*/
+                  MACH_RCV_MSG | MACH_RCV_TIMEOUT,    /*option*/
+                  0,                                  /*send size*/
+                  sizeof(mach_msg_file_status_rcv_t), /*receive size*/
+                  local_port_,                        /*receive port*/
+                  100,             /*timeout, in milliseconds*/
+                  MACH_PORT_NULL); /*no notification*/
+    if (kr != MACH_MSG_SUCCESS) {
+        NSLog(@"failed to receive Seafile Client's reply");
+        NSLog(@"mach error %s", mach_error_string(kr));
+        connectionBecomeInvalid();
+        return;
+    }
+    if (recv_msg_header->msgh_id != recv_msgh_id) {
+        NSLog(@"mach error unmatched message id %d, expected %d",
+              recv_msg_header->msgh_id, recv_msgh_id);
+        connectionBecomeInvalid();
+        return;
+    }
+    uint32_t status = recv_msg.status;
+    if (status >= PathStatus::MAX_SYNC_STATUS)
+        status = PathStatus::SYNC_STATUS_NONE;
+
+    // copy to heap before starting block
+    std::string repo_id = repo;
+    std::string path = fileName;
+    dispatch_async(dispatch_get_main_queue(), ^{
+      [parent_ updateFileStatus:repo_id.c_str()
+                           path:path.c_str()
+                         status:status];
+    });
+    mach_msg_destroy(recv_msg_header);
+}
diff --git a/fsplugin/Info.plist b/fsplugin/Info.plist
new file mode 100644 (file)
index 0000000..0bad0e4
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleDisplayName</key>
+       <string>Seafile FinderSync</string>
+       <key>CFBundleExecutable</key>
+       <string>Seafile FinderSync</string>
+       <key>CFBundleIconFile</key>
+       <string>seafile</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.seafile.seafile-client.findersync</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>Seafile FinderSync</string>
+       <key>CFBundlePackageType</key>
+       <string>XPC!</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>10.10</string>
+       <key>LSUIElement</key>
+       <true/>
+       <key>NSExtension</key>
+       <dict>
+               <key>NSExtensionAttributes</key>
+               <dict/>
+               <key>NSExtensionPointIdentifier</key>
+               <string>com.apple.FinderSync</string>
+               <key>NSExtensionPrincipalClass</key>
+               <string>FinderSync</string>
+       </dict>
+       <key>NSHumanReadableCopyright</key>
+       <string>Copyright © 2015 海文互知. All rights reserved.</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/fsplugin/bg_BG.lproj/Localizable.strings b/fsplugin/bg_BG.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/bg_BG.lproj/Localizable.strings differ
diff --git a/fsplugin/build.sh b/fsplugin/build.sh
new file mode 100755 (executable)
index 0000000..a18bd9b
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+set -x
+set -e
+
+CURRENT_PWD="$(dirname "${BASH_SOURCE[0]}")"
+
+if [ "$(uname -s)" != "Darwin" ]; then
+  echo "don't run it if you are not using Mac OS X"
+  exit -1
+fi
+
+export CC=$(xcrun -f clang)
+export CXX=$(xcrun -f clang)
+unset CFLAGS CXXFLAGS LDFLAGS
+
+pushd $CURRENT_PWD
+CONFIG=Debug
+if [ a"$1" != "adebug" ]; then
+  rm -rf CMakeCache.txt CMakeFiles
+  CONFIG=Release
+fi
+cmake -G Xcode -DCMAKE_BUILD_TYPE="$CONFIG"
+xcodebuild clean
+xcodebuild -jobs "$(sysctl -n hw.ncpu)" -configuration "$CONFIG"
+popd
+
diff --git a/fsplugin/ca.lproj/Localizable.strings b/fsplugin/ca.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/ca.lproj/Localizable.strings differ
diff --git a/fsplugin/cs_CZ.lproj/Localizable.strings b/fsplugin/cs_CZ.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..122e603
Binary files /dev/null and b/fsplugin/cs_CZ.lproj/Localizable.strings differ
diff --git a/fsplugin/de_DE.lproj/Localizable.strings b/fsplugin/de_DE.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..b353d5b
Binary files /dev/null and b/fsplugin/de_DE.lproj/Localizable.strings differ
diff --git a/fsplugin/el_GR.lproj/Localizable.strings b/fsplugin/el_GR.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..d2d1609
Binary files /dev/null and b/fsplugin/el_GR.lproj/Localizable.strings differ
diff --git a/fsplugin/en.lproj/Localizable.strings b/fsplugin/en.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/en.lproj/Localizable.strings differ
diff --git a/fsplugin/es.lproj/Localizable.strings b/fsplugin/es.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..0034cd3
Binary files /dev/null and b/fsplugin/es.lproj/Localizable.strings differ
diff --git a/fsplugin/es_AR.lproj/Localizable.strings b/fsplugin/es_AR.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..0034cd3
Binary files /dev/null and b/fsplugin/es_AR.lproj/Localizable.strings differ
diff --git a/fsplugin/es_MX.lproj/Localizable.strings b/fsplugin/es_MX.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..0034cd3
Binary files /dev/null and b/fsplugin/es_MX.lproj/Localizable.strings differ
diff --git a/fsplugin/et_EE.lproj/Localizable.strings b/fsplugin/et_EE.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/et_EE.lproj/Localizable.strings differ
diff --git a/fsplugin/fr_FR.lproj/Localizable.strings b/fsplugin/fr_FR.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..d671522
Binary files /dev/null and b/fsplugin/fr_FR.lproj/Localizable.strings differ
diff --git a/fsplugin/he_IL.lproj/Localizable.strings b/fsplugin/he_IL.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/he_IL.lproj/Localizable.strings differ
diff --git a/fsplugin/hu_HU.lproj/Localizable.strings b/fsplugin/hu_HU.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..2fc7737
Binary files /dev/null and b/fsplugin/hu_HU.lproj/Localizable.strings differ
diff --git a/fsplugin/is.lproj/Localizable.strings b/fsplugin/is.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..1590750
Binary files /dev/null and b/fsplugin/is.lproj/Localizable.strings differ
diff --git a/fsplugin/it.lproj/Localizable.strings b/fsplugin/it.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..eff60b0
Binary files /dev/null and b/fsplugin/it.lproj/Localizable.strings differ
diff --git a/fsplugin/ja.lproj/Localizable.strings b/fsplugin/ja.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..3fdcc3f
Binary files /dev/null and b/fsplugin/ja.lproj/Localizable.strings differ
diff --git a/fsplugin/ko_KR.lproj/Localizable.strings b/fsplugin/ko_KR.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..6bbcc79
Binary files /dev/null and b/fsplugin/ko_KR.lproj/Localizable.strings differ
diff --git a/fsplugin/lv.lproj/Localizable.strings b/fsplugin/lv.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..413e667
Binary files /dev/null and b/fsplugin/lv.lproj/Localizable.strings differ
diff --git a/fsplugin/nb_NO.lproj/Localizable.strings b/fsplugin/nb_NO.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..bafe54f
Binary files /dev/null and b/fsplugin/nb_NO.lproj/Localizable.strings differ
diff --git a/fsplugin/nl_BE.lproj/Localizable.strings b/fsplugin/nl_BE.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/nl_BE.lproj/Localizable.strings differ
diff --git a/fsplugin/nl_NL.lproj/Localizable.strings b/fsplugin/nl_NL.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/nl_NL.lproj/Localizable.strings differ
diff --git a/fsplugin/pl_PL.lproj/Localizable.strings b/fsplugin/pl_PL.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..e03e6bf
Binary files /dev/null and b/fsplugin/pl_PL.lproj/Localizable.strings differ
diff --git a/fsplugin/pt_BR.lproj/Localizable.strings b/fsplugin/pt_BR.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/pt_BR.lproj/Localizable.strings differ
diff --git a/fsplugin/pt_PT.lproj/Localizable.strings b/fsplugin/pt_PT.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/pt_PT.lproj/Localizable.strings differ
diff --git a/fsplugin/ru.lproj/Localizable.strings b/fsplugin/ru.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..f265f4d
Binary files /dev/null and b/fsplugin/ru.lproj/Localizable.strings differ
diff --git a/fsplugin/seafile-findersync-arch.svg b/fsplugin/seafile-findersync-arch.svg
new file mode 100644 (file)
index 0000000..6df119d
--- /dev/null
@@ -0,0 +1,2 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="779px" height="211px" version="1.1" content="&lt;mxfile userAgent=&quot;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36&quot; version=&quot;6.7.8&quot; editor=&quot;www.draw.io&quot; type=&quot;google&quot;&gt;&lt;diagram id=&quot;b4ffe93b-e81e-3163-fac6-cc86925c5d9a&quot; name=&quot;Page-1&quot;&gt;3Zhdb9owFIZ/DdJ20SqO88Ul0LJOaqVqTFp3aZJD4s3EkWMK9NfPThySNJC2WoFuQQL7tZ34POccx2aAJ8vNF0Gy5I5HwAa2FW0G+Gpg28PAVt9a2JaC43mlEAsalRKqhRl9AiNaRl3RCPJWR8k5kzRriyFPUwhlSyNC8HW724Kz9lMzEkNHmIWEddUfNJJJqQa2V+s3QOOkejLyhmXLklSdjSV5QiK+bkj4eoAngnNZlpabCTDNruJSjpseaN1NTEAqXzMAOwuA0LIcP5g7AQ4vkLHhkbCVsdbMVG4r89cJlTDLSKjra+XhAR4ncslUDaliRPIEIlNZUMYmnHFRDMWRC0HkKD2Xgv+GRktgz7EKAzw2zwchYXPQKrRjpWIM+BKk2KouZoDjBOUQE1/IM7jXtbewY7Sk4aldhBETIfHu3jVEVTAc9zN1QhcvfKSiPIwC33IuUIcgRCqeTJULmfCYp4Rd1+pY8FUaFRStNl3YUPnQKP/UXS5dXUvVRB/MiKJSt/0CKbcmkchKciXVz73lPDN3zCURcqRTRAkhI3lOw0qeUlZNojRIW9HvIWU0X4kQDgWba5KXiBhkb0R2fS2AEUkf2zP4G78dnN6RcmHh6s++XPCK631yAVUh3ZMLtnesXOgyRR2mU6oiXbyV7HugeZmMfzow9svBFqtVITtouHnbkXnV3Xrzuum2182dpc11096DBNnHQNJ9FZWhMtum4S3NJaRHCpsDzulya3BBlnfpNS4fnQqT34PphufyvIg2/Xg+BMGgQ/BbFk4Y1dZ+BHg2wpe4cTn4A8FD+PwL186ynoXL3rfhOw4SpycjTxpW+HXUmnF0uuV92ENJ6Z+mX+v65/MCOw8g1F3ZZ0DULhKUOJ3ds1VMU01KrPRPUc5JGs35pstLcZBtRAJy+mSSTh8ZMk5TWczfHQ/cK6Xok0JeHhr0AMJonKoyg4W+lYZL1aF4ZGSpTxHjXLmEpvH34khx4bzTTs19tlUL9kTucN9e7Sh+6b4var+MsoxBN7//afwufhn/seh3TtPdffIdCZN7dZz9v6Bj/9lm3H/l8eTt0FW1/supaGv8b4ev/wA=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g transform="translate(0.5,0.5)"><rect x="438" y="0" width="340" height="210" fill="#d5e8d4" stroke="#82b366" stroke-dasharray="3 3" pointer-events="none"/><path d="M 366.37 105 L 431.63 105" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 361.12 105 L 368.12 101.5 L 366.37 105 L 368.12 108.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 436.88 105 L 429.88 108.5 L 431.63 105 L 429.88 101.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><rect x="100" y="0" width="260" height="210" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="none"/><rect x="0" y="0" width="70" height="210" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(17.5,98.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="34" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 36px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Finder</div></div></foreignObject><text x="17" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Finder</text></switch></g><rect x="448" y="50" width="106.67" height="120" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(448.5,103.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="104" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 104px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">FinderSyncListener</div></div></foreignObject><text x="52" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">FinderSyncListener</text></switch></g><rect x="554.67" y="50" width="106.67" height="120" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(565.5,103.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="85" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 87px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">FinderSyncHost</div></div></foreignObject><text x="43" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">FinderSyncHost</text></switch></g><rect x="661.33" y="50" width="106.67" height="120" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(687.5,103.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="53" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 53px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">RpcClient</div></div></foreignObject><text x="27" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">RpcClient</text></switch></g><rect x="230" y="50" width="120" height="120" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(243.5,103.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="92" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 92px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">FinderSyncClient</div></div></foreignObject><text x="46" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">FinderSyncClient</text></switch></g><rect x="110" y="50" width="120" height="120" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(111.5,96.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="116" height="26" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 116px; white-space: normal; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">FinderSync (FIFinderSync)</div></div></foreignObject><text x="58" y="19" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">FinderSync (FIFinderSync)</text></switch></g><g transform="translate(141.5,22.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="179" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Seafile FSPlugin (run in sandbox)</div></div></foreignObject><text x="90" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Seafile FSPlugin (run in sandbox)</text></switch></g><g transform="translate(521.5,22.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="74" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Seafile Applet</div></div></foreignObject><text x="37" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Seafile Applet</text></switch></g><g transform="translate(369.5,112.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="51" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">MachPort</div></div></foreignObject><text x="26" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">MachPort</text></switch></g></g></svg>
\ No newline at end of file
diff --git a/fsplugin/seafile-fsplugin.entitlements b/fsplugin/seafile-fsplugin.entitlements
new file mode 100644 (file)
index 0000000..786acc5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>com.apple.security.app-sandbox</key>
+    <true/>
+    <key>com.apple.security.files.user-selected.read-only</key>
+    <true/>
+    <key>com.apple.security.application-groups</key>
+    <array>
+        <string>com.seafile.seafile-client.findersync</string>
+    </array>
+</dict>
+</plist>
diff --git a/fsplugin/sk_SK.lproj/Localizable.strings b/fsplugin/sk_SK.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/sk_SK.lproj/Localizable.strings differ
diff --git a/fsplugin/status-done.icns b/fsplugin/status-done.icns
new file mode 100644 (file)
index 0000000..6f2282d
Binary files /dev/null and b/fsplugin/status-done.icns differ
diff --git a/fsplugin/status-error.icns b/fsplugin/status-error.icns
new file mode 100644 (file)
index 0000000..9a080a7
Binary files /dev/null and b/fsplugin/status-error.icns differ
diff --git a/fsplugin/status-ignored.icns b/fsplugin/status-ignored.icns
new file mode 100644 (file)
index 0000000..856dba2
Binary files /dev/null and b/fsplugin/status-ignored.icns differ
diff --git a/fsplugin/status-locked-by-me.icns b/fsplugin/status-locked-by-me.icns
new file mode 100644 (file)
index 0000000..16a0c5c
Binary files /dev/null and b/fsplugin/status-locked-by-me.icns differ
diff --git a/fsplugin/status-locked.icns b/fsplugin/status-locked.icns
new file mode 100644 (file)
index 0000000..6052ad5
Binary files /dev/null and b/fsplugin/status-locked.icns differ
diff --git a/fsplugin/status-syncing.icns b/fsplugin/status-syncing.icns
new file mode 100644 (file)
index 0000000..891bda3
Binary files /dev/null and b/fsplugin/status-syncing.icns differ
diff --git a/fsplugin/sv.lproj/Localizable.strings b/fsplugin/sv.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..bb8e2b6
Binary files /dev/null and b/fsplugin/sv.lproj/Localizable.strings differ
diff --git a/fsplugin/tr.lproj/Localizable.strings b/fsplugin/tr.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/tr.lproj/Localizable.strings differ
diff --git a/fsplugin/uk.lproj/Localizable.strings b/fsplugin/uk.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..fad5091
Binary files /dev/null and b/fsplugin/uk.lproj/Localizable.strings differ
diff --git a/fsplugin/zh_CN.lproj/Localizable.strings b/fsplugin/zh_CN.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..143e36e
Binary files /dev/null and b/fsplugin/zh_CN.lproj/Localizable.strings differ
diff --git a/fsplugin/zh_TW.lproj/Localizable.strings b/fsplugin/zh_TW.lproj/Localizable.strings
new file mode 100644 (file)
index 0000000..ddaad09
Binary files /dev/null and b/fsplugin/zh_TW.lproj/Localizable.strings differ
diff --git a/i18n/seafile_bg_BG.ts b/i18n/seafile_bg_BG.ts
new file mode 100644 (file)
index 0000000..71e7c66
--- /dev/null
@@ -0,0 +1,3274 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="bg_BG" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>close</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>0</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_ca.ts b/i18n/seafile_ca.ts
new file mode 100644 (file)
index 0000000..f7d0b04
--- /dev/null
@@ -0,0 +1,3288 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="ca" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>No s&apos;ha pogut accedir a la base de dades</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Autorització expirada, si us plau torni a iniciar sessió</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Configuració del compte</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Si us plau indiqui l&apos;adreça del servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 no és una adreça de servidor vàlida</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>No s&apos;ha pogut guardar la informació del compte</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>No s&apos;han pogut guardar els canvis: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>La informació del compte actual s&apos;ha actualitzat correctament
+</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diàleg</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Adreça del servidor</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Email</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>D&apos;acord</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancel·lar</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>No s&apos;ha pogut desincronitzar les biblioteques d&apos;aquest compte: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>clic per obrir la pàgina web</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>versió pro</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Sense compte</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Triar</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Configuració del compte</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Iniciar sessió</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Esborrar</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Afegir un compte</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Tancar sessió</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>no està autenticat</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Tasques de descarrega </translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>Elimina les tasques finalitzades</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>No hi ha cap descarrega</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Buida</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Tanca</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Llibreria</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Ruta</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Cancel·la la tasca</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>cancel·la la tasca</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Elimina la tasca </translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>No s&apos;ha pogut cancel·lar la tasca:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>No s&apos;ha pogut eliminar la tasca:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimitza</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Tanca</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>velocitat de descarrega</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>velocitat de pujada</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Seleccioneu el directori a sincronitzar</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>no hi ha cap servidor connectat</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>tots els servidors estan connectats</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>alguns servidors no estan connectats</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulari</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logotip</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimitza</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>tanca</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Seleccioneu</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>o arrossega el directori a sincronitzar</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>velocitat de descarrega</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>estreny </translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>velocitat de pujada</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>eixample</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>No s&apos;ha pogut crear la configuració del ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>No s&apos;ha pogut llegir %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Crea una llibreria</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Seleccioneu un directori</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Creant...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Seleccioneu el directori a sincronitzar</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>El directori %1 no existeix</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Introduïu el nom</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Introduïu la contrasenya</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Les contrasenyes no coincideixen</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconegut</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>No s&apos;ha pogut descarregar:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Ruta:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Selecciona</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nom:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>encriptat</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contrasenya:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Repetiu la contrasenya:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>text d&apos;estat</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>D&apos;acord</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancel·la</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Introduïu la contrasenya</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Sincronitza la llibreria &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>No s&apos;ha pogut descarregar: 
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Descarrega la llibreria</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>seleccioneu...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>La contrasenya d&apos;aquesta llibreria:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>D&apos;acord</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancel·la</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancel·lar</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 inicialitzat</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Seleccioneu un directori</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>La inicialització no ha finalitzat. Esteu segur que voleu sortir?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>El directori %1 no existeix</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logotip</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Seleccioneu...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Següent</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancel·la</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Verificant la llibreria per defecte...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Creant la llibreria per defecte...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>No s&apos;ha pogut crear la llibreria per defecte:
+
+Cal un servidor versió 2.1 o superior.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Descarregant la llibreria per defecte...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>La llibreria per defecte s&apos;ha descarregat.
+Podeu clicar &quot;Obre&quot; per visualitzar-la.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>S&apos;ha produït un error al descarregar la llibreria: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>No s&apos;ha pogut descarregar la llibreria:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Omet</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Executa en segon pla</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Obre</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Acaba</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Descarrega la llibreria per defecte</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sí</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logotip</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Afegeix un compte</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Iniciant sessió...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Error de xarxa:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Atenció:&lt;/b&gt; El certificat SSL d&apos;aquest servidor no és de confiança, voleu continuar?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Introduïu la direcció del servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 no és una direcció de servidor vàlida</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Introduïu un nom d&apos;usuari</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>No s&apos;ha pogut guardar el compte actual</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Introduïu la contrasenya</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>El correu electrònic o la contrasenya són incorrectes</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Error intern del servidor</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>No s&apos;ha pogut iniciar sessió: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>No s&apos;ha pogut iniciar sessió</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logotip</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contrasenya:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>text d&apos;estat</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Inicia sessió</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancel·la</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Afegir un compte</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Refresca</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diàleg</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>sincronitzat</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indexant els fitxers</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>inicialitzant la sincronització</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>descarregant</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>pujant</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>Mesclant </translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>Esperant per sincronitzar</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>el servidor no està connectat</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>autentificant al servidor</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>la sincronització automàtica està desactivada</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>desconegut</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>El servidor s&apos;ha eliminat</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>No has iniciat sessió al servidor</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>No teniu permís per accedir aquesta llibreria</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>S&apos;ha superat el límit de capacitat de la llibreria</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>El servei remot no està disponible</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>La llibreria s&apos;ha eliminat al servidor</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>inicialitzant...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>connectant al servidor...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indexant els fitxers...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Creant el directori...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Mesclant els canvis...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Finalitzat</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Cancelant</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Cancel·lat</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Llibreria &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Aquesta llibreria encara no s&apos;ha descarregat</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Error:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Icona</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>Nom</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Etiqueta</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Propietari:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Última modificació:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>mida:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Ruta local:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Estat:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Repo-Estat</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nom:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Tanca</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Aquesta llibreria no s&apos;ha descarregat</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Actualitzat recenment</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Llibreries personals</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Sub-Llibreries</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desactiva la sincronització automàtica</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Activa la sincronització automàtica</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Sincronitza aquesta llibreria</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Cancel·la la descarrega</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Cancel·la la descarrega d&apos;aquesta llibreria</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Obre un directori</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>obre un directori local</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Desincronitza</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>Deixa de sincronitzar aquesta llibreria</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Mostra a la web</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>mostra aquesta llibreria a seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>No s&apos;ha pogut sincronitzar la llibreria &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>No s&apos;ha pogut cancel·lar la tasca:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>S&apos;ha cancel·lat la descarrega</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>D&apos;acord</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancel·lar</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>D&apos;acord</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconegut</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desactiva la sincronització automàtica</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Activa la sincronització automàtica</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Sortir</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Mostra la finestra</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Configuració</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Sobre</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Mostra informació sobre l&apos;aplicació</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Ajuda a la web</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>La sincronització automàtica està desactivada</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>alguns servidors no estan connectats</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Estat de la connexió remota</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>connectat</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>desconnectat</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Tanca</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diàleg</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>D&apos;acord</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancel·lar</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Configuració</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Oculta la finestra principal al iniciar</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Notifica quan les llibreries estan sincronitzades</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Límit de baixada (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Límit de pujada (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>0</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>D&apos;acord</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancel·la</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>D&apos;acord</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diàleg</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Desinstal·la %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Voleu eliminar la informació del compte %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Eliminant informació del compte...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>text</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sí</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_cs_CZ.ts b/i18n/seafile_cs_CZ.ts
new file mode 100644 (file)
index 0000000..e1faaa6
--- /dev/null
@@ -0,0 +1,3297 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="cs_CZ" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>O aplikaci %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>O aplikaci</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Zkontrolovat aktualizace</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>Nepodařilo se otevřít databázi účtů</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Přihlášení vypršelo, přihlašte se prosím</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Nastavení účtu</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Napište, prosím, adresu serveru</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 není platná adresa serveru</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Nelze uložit informace o účtu</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Nelze uložit změny: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Informace o účtu byly úspěšně změněny</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Adresa serveru</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Email</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Nepodařilo se odebrat synchronizaci knihoven tohoto účtu: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>Otevřít v prohlížeči</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>pro verze</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Žádný účet</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Vybrat</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Nastavení účtu</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Přihlásit</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Smazat</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Přidat účet</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Odhlásit</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>nepřihlášeno</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulář</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Účet</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>email</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>server</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Aktivita souborů je podporována pouze v %1 Server Professional Edition</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>opakovat</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Nepodařilo se získat informace o aktivitách. Prosím% 1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Nahrávání úspěšné</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Soubor &quot;%1&quot;
+nahrán úspěšně.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Soubor &quot;%1&quot;
+nahrání selhalo.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Chyba oprávnění!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Přihlášení vypršelo</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Soubor neexistuje</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Chyba nahrávání: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Chyba při vytváření složky profilových fotografií</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Kontroluji oprávnění</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Stahování</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>odstranit všechny úspěšné úkoly</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Neprobíhá žádné stahování</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Vyčistit</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zavřít</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Knihovna</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Cesta</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Zrušit tuto úlohu</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>zrušit tuto úlohu</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Odebrat tuto úlohu</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Nemohu zrušit tuto úlohu:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Nemohu odebrat tuto úlohu:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimalizovat</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zavřít</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Knihovny</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Oblíbené</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Aktivity</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Hledat</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>aktuální rychlost stahování</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>aktuální rychlost uploadu</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Vyberte adresář k synchronizaci</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>není připojen žádný server</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>všechny servery jsou připojeny</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>některé servery nebyly připojeny</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulář</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimalizovat</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>zavřít</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Vybrat</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>značka</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>nebo přetáhnout složku k synchronizaci</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>rychlost stahování</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>šipka dolů</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>rychlost uploadu</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>šipka nahoru</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Chyba při vytváření ccnet konfigurace</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Nepodařilo se vytvořit předkonfigurační adresář &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>chyba při čtení %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Vytvořit knihovnu</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Vyberte adresář</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Vytvářím...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Nepodařilo se vygenerovat šifrovací klíč pro knihovnu</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Vyberte adresář k synchronizaci</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Adresář %1 neexistuje</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Vložte jméno</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Vložte heslo</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Hesla se neshodují</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Neznámá chyba</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Nelze přidat stahování:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Nelze vytvořit knihovnu na serveru:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Cesta:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Vybrat</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Název:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>šifrováno</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Heslo:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Heslo znovu:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>stavový text</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>%1 klient se nepodařilo spustit</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Vložte heslo</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Synchronizovat knihovnu %1</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Synchronizovat složku &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Synchronizovat do složky</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>nebo</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>Synchronizovat existující adresář</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>Vytvořit nový synchronizační adresář</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Synchronizovat tento existující adresář</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Prosím zvolte složku</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>Složka neexistuje</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Prosím zvolte složku k dynchronizaci</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Vaše organizace znemožnila umístění knihovny mimo adresář %1.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Dochází ke konfliktu se souborem &quot;%1&quot;, prosím zvolte jinou složku.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Dochází ke konfliktu s knihovnou &quot;%1&quot;, prosím zvolte jinou složku.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>Složka &quot;%1&quot; již existuje.Jste si jistí že s ní chcete synchronizovat (obsah bude sloučen)?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Klikněte Ne pro synchronizaci s novou složkou</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Nepodařilo se najít alternativní název adresáře</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Nelze přidat stahování:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Nepodařilo se stáhnout informace o repozitáři:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Stáhnout knihovnu</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>vybrat...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Heslo pro tuto knihovnu:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Podrobnosti o změnách</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Přidané soubory</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Smazané soubory</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Změněné soubory</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Přidané složky</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Smazané složky</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Otevřít</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Otevřít &amp; rodičovská složka</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Prohlížeč souborů v Cloudu</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Zpět</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Vpřed</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Domů</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Nahrát soubory</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Nahrát adresář</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Nemáte oprávnění pro nahrání souborů do této knihovny</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Vytvořit adresář</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Obnovit</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 položek</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Jméno adresáře</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Neplatné jméno adresáře!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>Jméno &quot;%1&quot; uz existuje.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>opakovat</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Chyba při stahování informací o souborech&lt;br/&gt;
+Prosím %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>Složka je prázdná</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Vložte název souboru, do kterého si přejete uložit...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Nelze odstranit soubor &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Vložte cestu ke knihovně, do které si přejete ukládat...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Přejete si přepsat existující soubor &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>Soubor &quot;%1&quot; nebyl synchronizován</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Soubor %1 již existuje.&lt;br/&gt;Chcete ho přepsat?&lt;br/&gt;&lt;small&gt;(Zvolte Ne pokud ho chcete nahrát s jiným názvem).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Soubor neexistuje</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Selhalo stažení souboru: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Vyberte soubor k nahrání</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Vybrat adresář k nahrání</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Přejmenovat</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Opravdu chcete smazat tyto položky</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Vytváření adresáře selhalo</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Uzamčení souboru selhalo</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Vybrat soubor pro aktualizaci %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Přejmenování selhalo</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Odstranění selhalo</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Sdílení selhalo</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Nelze vložit soubory z toho samého adresáře</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>Nelze vložit složku</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Kopírování selhalo</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Přesun selhal</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Vytvoření knihovny selhalo</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Nemáte práva nahrát tuto složku</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Přihlášení vypršelo</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Chyba oprávnění!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Knihovna/složka nenalezena.</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Vyhledat soubory</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>Čekající</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Nahrát</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Nahrávám %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Stáhnout</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Stahuji %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 z %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>Selhalo nahrání souboru: %1, opakovat?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>Opakovat</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Přeskočit</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Přerušit</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>Ukládám</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>Uložení souboru selhalo</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Název</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Velikost</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Poslední úprava</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Zobrazit ve složce</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Zobrazit ve složce</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Operace zrušena</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>čekající</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>úloha zrušena</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Vnitřní chyba serveru</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Kvóta na severu je obsazená</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>uzamčeno %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Název</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Velikost</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Poslední úprava</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Uložit jako...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Zamknout</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Přejmenovat</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Smazat</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Sdílet se skupinou</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Aktualizovat</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Kopírovat</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Vyjmou&amp;t</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Vložit</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Zrušit stahování</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Synchronizovat tento adresář</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Tato funkcionalita je dostupná pouze v PRO verzi
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>&amp;Vygenerovat odkaz ke stažení</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Sdílet s uživatelem</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>Vygenerovat %1 interní odkaz</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Uložit jako do...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Odemknout</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>S oprávněním ke čtení není možno odstranit soubory </translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Nelze vyjmout soubory pouze pro čtení</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>Opakovat upload</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>Smazat místní verzi</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Selhalo vytváření adresářů</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Selhalo vytváření dočasných souborů</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Selhalo zapsání souboru na disk</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Selhalo odstranění starší verze stahovaného souboru</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Selhalo přesunutí souboru</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 inicializace</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Vyberte adresář %1</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Vyberte adresář</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Inicializace není kompletní. Opravdu ukončit?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Adresář %1 neexistuje</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Vyberte adresář</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Prosím vyberte adresář. V něm vytvoříme podadresář %1. Až stáhnete knihovnu, uloží se zde.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Vybrat...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Další</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Kontrola výchozí knihovny ...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Vytvářím výchozí knihovnu...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Nepodařilo se vytvoření základní knihovny:
+
+Verze serveru musí být 2.1 nebo vyšší.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Nepodařilo se získat výchozí knihovnu:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Nepodařilo se vytvořit výchozí knihovnu:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Stahuji výchozí knihovnu...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Nelze stáhnout výchozí knihovnu:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Výchozí knihovna byla stažena.
+Klikněte na tlačítko &quot;Otevřít&quot; pro zobrazení.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Chyba při stahování výchozí knihovny:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Nelze stáhnout výchozí knihovnu:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Přeskočit</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Spustit na pozadí</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Otevřít</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Dokončit</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Stáhnout výchozí knihovnu:</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ano</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>nahrát další</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>Nahrání log souborů selhalo</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Nahrát log soubory</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Chyba oprávnění!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Knihovna/složka nenalezena.</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Přihlášení vypršelo</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>Nahrání log souborů selhalo :%1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>Úspěšně byly nahrány log soubory</translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>Komprimuji</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Přidat účet</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>Single Sign On - SSO</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Znovu přihlásit</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Přihlašuji se...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Chyba sítě:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Varování:&lt;/b&gt; SSL certifikát serveru není důvěryhodný, přesto pokračovat?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Vložte adresu serveru</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 není platná adresa serveru</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Vaše uživatelské jméno</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Název počítače</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Chyba při ukládání informací o účtu</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1 adresa serveru</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>Adresa serveru nesmí být prázdná</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Vložte heslo</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Nesprávný email nebo heslo</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Přihlašujete se příliš často, prosím počkejte chvíli</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Vnitřní chyba serveru</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Chyba při přihlášení: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Chyba při přihlášení</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Server:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Například: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>nebo http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Heslo:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>stavový text</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Název počítače:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Email / Uživ. jméno:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>například Honzův počitač</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Login</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Automatické přihlášení</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Jste odhlášen. Prosím</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>Login</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Přidat účet</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Obnovit</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Sdílet %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Vložte název skupiny</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Vložte uživatelské jméno nebo emailovou adresu</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Úspěšně aktualizováno</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>Operace sdílení selhala: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Úspěšně odstraněno</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Nepodařilo se stáhnout informace pro sdílení adresáře</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Nepodařilo se stáhnout informace o skupinách a kontaktech</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Prosím zadejte uživatelské jméno</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Prosím zadejte název skupiny</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>Skupina &quot;%1&quot; neexistuje</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Se skupinou %1 je již sdíleno</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>S uživatelem %1 je již sdíleno</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Stále probíhá předchozí operace</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Sdílet s:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Sdílet</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Oprávnění</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Číst a zapisovat</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Pouze číst</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zavřít</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>synchronizováno</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indexuji soubory</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>Synchronizace zhájena</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>stahuji</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>Nahrávám</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>synchronizace spojení</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>čekám na synchronizaci</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>sever není připojen</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>autentizace serveru</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>automatická synchronizace je vypnuta</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>neznámý/á</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Server byl odebrán</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Nejste přihlášeni na server</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Nemáte právo přístupu k této knihovně</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Byl dosažen datový limit na severu pro majitele této knihovny </translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Vzdálená služba není dostupná</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Přístup ke službě zakázán</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Vnitřní chyba dat</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Problém při startu nahrávání</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Chyba při startu stahování</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Knihovna je poškozena na serveru</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Chyba při sloučení</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Verze serveru je zastaralá</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Neznámá chyba</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Chyba připojení</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>Nemohu se připojit k serveru</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>Chyba při navazování zabezpečeného připojení. Zkontrolujte SSL certifikát serveru</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Chyba serveru</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Nesprávný požadavek</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>Nedostatek paměti</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>Knihovna je smazána na serveru</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>Knihovna je poškozena na serveru</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Kvóta na severu je obsazená</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Vnitřní chyba serveru</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Váš klient %1 je zastaralý</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Synchronizace této knihovny selhala</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Soubory jsou uzamčeny jinou aplikací</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Knihovna je smazána na serveru</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Chyba během přístupu k lokálnímu adresáři</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>Inicializuji...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>Chyba během indexace lokálních souborů</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>Chyba při vytváření lokálních souborů.</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>Chyba při slučování změn lokálních souborů.</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Nesprávné heslo. Stáhněte, prosím, znovu</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Vnitřní chyba</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>připojuji server...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indexuji soubory...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Stahuji seznam souborů...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Stahuji soubory...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Vytvářím adresář...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Sloučit změny souborů ...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Hotovo</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Rušení</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Zrušeno</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>Chyba SSL</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Chyba sítě: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Chyba serveru</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>Chyba při otevírání databáze certifikátů</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>Soubor &quot;%1&quot; v &quot;%2&quot; neexistuje</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 nelze najít aplikaci, která otevře soubor %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Vytvořena knihovna &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Smazána knihovna &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Přejmenovat %1 na</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Není možné stáhnout &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>kopírování selhalo</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Přidáno</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Smazáno</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Odebráno</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Upraveno</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Přejmenováno</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Přidáno nebo upraveno</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Přemístěno</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Přidán adresář</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Odebraný adresář</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Přejmenovaný adresář</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Přesunutý adresář</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>soubory</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>adresáře</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>a %1 dalších</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Stav knihovny navrácen k</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Stav souboru &quot;%1&quot; byl navrácen k &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Smazaný adresář byl obnoven</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Název nebo popis knihovny byl změněn</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>Automatické spojení systémem %1</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Právě teď</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>Včera</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>před %1 dny</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>před 1 hodinou</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>před %1 hodinami</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>před minutou</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>před %1 minutami</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Not Part of Certificate&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Synchronizovat tuto knihovnu s:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Synchronizovat tento adresář s:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Složka</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Dokument pouze ke čtení</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Dokument</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF Dokument</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Obrázek</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Dokument</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Zvuk</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Video soubor</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Word Dokument</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>PowerPoint Dokument</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Excel Dokument</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>Cesta &quot;%1&quot; koliduje se systémovou cestou</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>Cesta &quot;%1&quot; koliduje s existující knihovnou</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>nahrávám seznam souborů</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>Soubor je uzamčen jinou aplikací</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>Složka je uzamčena jinou aplikací</translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>Soubor je uzamčen jiným uživatelem</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>Nesprávná cesta</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Chyba indexace</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>Soubor neexistuje</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Knihovna &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Tato knihovna nebyla stažena</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Chyba:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>každých %1 vteřin</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>RepoIcon</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>RepoName</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>TextLabel</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Vlastník:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Poslední modifikace:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Velikost:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Místní cesta:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Status:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>RepoStatus</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Název:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Interval synchronizace:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zavřít</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Tato knihovna nebyla stažena</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>Nepodařilo se otevřít soubor &quot;%1&quot; v neexistující knihovně &quot;%2&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Nedávno aktualizované</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Moje knihovny</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Podknihovny</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Sdíleno se mnou</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Sdíleno se všemi</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Sdíleno se skupinama</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Synchronizované knihovny</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>spuštění synchronizace</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Zrušit automatickou synchronizaci</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Automatická synchronizace</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Zobrazit detaily</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Zobrazit detaily knihovny</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>Synchronizovat tuto knihovnu</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Synchronizovat tuto knihovnu</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Nedávno aktualizované</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Synchronizovat</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Okamžitě synchronizovat knihovnu</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>Zrušit stahování</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Zrušit stahování této knihovny</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Otevřít adresář</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>otevřít lokální adresář</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>&amp;Otevřít místní adresář</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Zrušit synchronizaci</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>Zrušit synchronizaci této knihovny</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>Zobrazit na serveru</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>Zobrazit tuto knihovnu na serveru</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Sdílet s uživatelem</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Sdílet tuto knihovnu s uživatelem</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Sdílet se skupinou</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Sdílet tuto knihovnu se skupinou</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Otevřít prohlížeč souborů cloudu</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>Otevřít tuto knihovnu v Prohlížeči souborů Cloudu</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>&amp;Zrušit sdílení</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>zrušit sdílení</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>Resynchronizovat knihovnu</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>Zrušit synchronizaci a znovu synchronizovat tuto knihovnu</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Nastavit synchronizaci &amp;Interval</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Chyba při rušení synchronizace &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Chyba při rušení ulohy:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Stahování bylo zrušeno</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>Přepsání souboru %1 sebou samým se nezdařilo</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Nelze smazat soubor &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Nelze nahrát soubor: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Interval synchronizace (ve vteřinách):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Nastavit interval synchronizace pro knihovnu &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>opakovat</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Nepodařilo se získat informace o knihovně&lt;br/&gt;Prosím %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Varování:&lt;/b&gt; SSL certifikát serveru není důvěryhodný, přesto pokračovat?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>přidání základního účtu se nezdařilo</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Nezdařilo se spuštění logu: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ano</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Ne</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>%1 Interní odkaz</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Zkopírovat do schránky</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Neznámá chyba</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Zrušit automatickou synchronizaci</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Automatická synchronizace</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Ukončit</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Zobrazit hlavní okno</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Nastavení</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Otevřít &amp;adresář %1</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>otevřít %1 adresář</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Otevřít adresář log souborů</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;O aplikaci</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Zobrazit informace O aplikaci</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Online nápověda</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Soubor</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>automatická synch. je zakázana</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Nahrávání</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Stahování</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>otevřít adresář s logy %1</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>otevřít online nápovědu %1</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>některé servery nejsou připojeny</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Zobrazit ve složce</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Zobrazit ve složce</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>zkusit znovu</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Hledání se nezdařilo &lt;br /&gt; Prosím %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Informace o serverech</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>připojeno</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>odpojeno</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zavřít</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Nastavte, prosím, heslo knihovny</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Zadejte heslo pro knihovnu %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Vložte heslo</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Nesprávné heslo</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Neznámá chyba</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Nastavení</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>Automaticky spustit %1 po přihlášení</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>Skrýt ikonu %1 ze spouštěče</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Žádný</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP Proxy</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5 Proxy</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Systémová proxy</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Byla provedena změna jazyka. Restartovat pro použití?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>Adresa proxy hostitele nesmí být prázdná</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>Port proxy je nesprávný</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>Uživatelské jméno proxy nesmí být prázdné</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>Uživatelské heslo proxy nesmí být prázdné</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Skrýt hlavní okno po startu</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Informovat, že knihovny byly synchromizovány</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Povolit synchronizaci pro dočasné soubory MSOffice/Libreoffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Download limit (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Upload limit (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Základní</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Nezrušit automaticky synchronizaci knihovny</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Nezrušit automaticky synchronizaci knihovny v případě, že je lokální adresář odstraněn nebo je nepřístupný z jiných důvodů</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Nezrušit synchronizaci knihovny pokud knihovna není nalezena na serveru</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Nezrušit synchronizaci knihovny pokud knihovna není nalezena na serveru</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Povolit rozšíření FinderSync</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Povolit rozšíření Průzkumníku souborů</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Neověřovat certifikát při HTTPS synchronizaci</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Povolit synchronizaci s existujícím adresářem pod jiným názvem</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Rozšířené</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Jazyk (vyžaduje restart)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Jazyk</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Typ proxy:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Host:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Port:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Uživatelské jméno</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Heslo:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Proxy server vyžaduje heslo</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Síť</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušit</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Číst a zapisovat</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Pouze číst</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Zrušit sdílení</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Vytvořeno %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Číst a zapisovat</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Pouze číst</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Skupina</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Uživatel</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Oprávnění</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Předchozí operace stále probíhá</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Sdílet odkaz</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Sdílet odkaz:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Přímé stažení</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Zkopírovat do schránky</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Nezabezpečené spojení</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 používá neplatný zabezpečovací certifikát. Spojení může být nezabezpečené. Opravdu chcete pokračovat?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Aktuální otisk RSA klíče je %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Předchozí otisk RSA klíče byl %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Zapamatovat výběr</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ano</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Ne</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp; Otevřít</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Otevřít soubor</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>zobrazit v prohlížeči</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>otevřít tento soubor v prohlížeči</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>opakovat</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Chyba při stahování informací o oblíbených souborech&lt;br&gt; Prosím %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Nemáte žádné oblíbené soubory.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Chyba synchronizace souborů</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Knihovna</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Chyba</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Odinstalovat %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Opravdu chcete odebrat informace o účtu %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Odebírám informace o účtu...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>text</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ano</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Ne</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_de_DE.ts b/i18n/seafile_de_DE.ts
new file mode 100644 (file)
index 0000000..54c78e8
--- /dev/null
@@ -0,0 +1,3305 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="de_DE" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>Über %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; REV %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>Über</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Auf Aktualisierungen prüfen</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>Fehler beim Aufruf der Datenbank</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Legitimierung abgelaufen, bitte erneut anmelden</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation>Entfernen des lokalen Tokens zum Synchronisieren nicht möglich: %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation>Abrufen der Informationen zum Synchronisieren nicht möglich: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Kontoeinstellungen</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Bitte geben Sie die Serveradresse ein</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 ist keine gültige Serveradresse. Haben Sie „http(s)://“ vorangestellt?</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Die Kontoinformationen konnten nicht gespeichert werden</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Die Änderungen konnten nicht gespeichert werden: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Die Kontoinformationen wurden aktualisiert</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Serveradresse</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>E-Mail</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>Möchten Sie das Konto %1 entfernen?&lt;br /&gt;&lt;br /&gt;Das Konto wird dann lokal entfernt. Alle Einstellungen zum Synchronisieren werden ebenfalls gelöscht. Das Konto auf dem Server wird nicht verändert.</translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Synchronisieren der Bibliothek von „%1“ konnte nicht aufgehoben werden</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>Zum Öffnen der Website anklicken</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>Pro Version</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Kein Konto</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Auswählen</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Kontoeinstellungen</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Anmelden</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Löschen</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Ein Konto hinzufügen</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Ausloggen</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>Nicht angemeldet</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formular</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Konto</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>E-Mail</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>Server</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>&lt;b&gt;Aktivitäten&lt;/b&gt; werden nur von %1 Pro unterstützt.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>wiederholen</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Informationen zur Aktivität waren nicht abrufbar. Bitte %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Erfolgreich hochgeladen</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Datei „%1“
+erfolgreich hochgeladen.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Datei „%1“
+wurde nicht hochgeladen.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Keine ausreichenden Rechte!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Legitimierung abgelaufen</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Datei ist nicht vorhanden</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation>Die Datei ist von %1 gesperrt, bitte versuchen Sie es später noch einmal</translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Fehler beim Hochladen: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Avatarordner konnte nicht erstellt werden</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Rechte werden geprüft</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Download-Aufgaben</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>Alle erfolgreich erledigten Aufgaben entfernen</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Keine Download-Aufgaben eingerichtet</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Leeren</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Schließen</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Bibliothek</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Pfad</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Diese Aufgabe abbrechen</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>diese Aufgabe abbrechen</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Diese Aufgabe entfernen</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Fehler beim Abbrechen dieser Aufgabe:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Fehler beim Entfernen dieser Aufgabe:
+
+ %1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimieren</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Schließen</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Bibliotheken</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Favoriten</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Aktivitäten</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Suche</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>aktuelle Download-Geschwindigkeit</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>aktuelle Upload-Geschwindigkeit</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Bitte einen Ordner zum Synchronisieren auswählen</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>kein Server verbunden</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>Alle Server verbunden</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>einige Server nicht verbunden</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formular</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>Logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimieren</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>schließen</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>…</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Ordner wählen</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>brand</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>oder ablegen</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>Download-Geschwindigkeit</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>Abwärtspfeil</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>Upload-Geschwindigkeit</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>Aufwärtspfeil</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Fehler beim Erstellen der ccnet-Konfiguration</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Fehler beim Erstellen des vorkonfigurierten Ordners „%1“</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>Fehler beim Lesen von %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Eine Bibliothek erstellen</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Bitte einen Ordner auswählen</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Wird erstellt …</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Fehler beim Verschlüsseln dieser Bibliothek</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Bitte wählen Sie den zu synchronisierenden Ordner</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Der Ordner %1 ist nicht vorhanden</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Bitte geben Sie den Namen ein</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Bitte geben Sie das Passwort ein</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Passwörter sind nicht identisch</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Unbekannter Fehler</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Download konnte nicht eingerichtet werden:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Fehler beim Erstellen der Bibliothek auf dem Server: %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Pfad:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Auswählen</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Name:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>verschlüsselt</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Passwort:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Passwort wiederholen:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>Status-Text</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>Fehler beim Initialisieren des %1-Clients </translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>%1 ist unerwartet abgebrochen</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Bitte geben Sie das Passwort ein</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Bibliothek „%1“ synchronisieren</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>„%1“ wird synchronisiert</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Bibliothek in folgendem Ordner speichern und synchronisieren:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>oder</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>mit vorhandenem Ordner synchronisieren</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>einen neuen Ordner zum Synchronisieren erstellen</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Mit diesem bereits vorhandenen Ordner synchronisieren:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Bitte wählen Sie einen Ordner</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>Der Ordner ist nicht vorhanden</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Bitte wählen Sie einen Ordner zum Synchronisieren</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Ihre Organisation erlaubt nicht, eine Bibliothek außerhalb des Ordners %1 abzulegen.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Konflikt mit der bereits vorhandenen Datei „%1“, bitte wählen Sie einen anderen Ordner.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Konflikt mit der bereits vorhandenen Bibliothek „%1“, bitte wählen Sie einen anderen Ordner.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>Der Ordner „%1“ ist bereits vorhanden. Möchten Sie ihn wirklich synchronisieren und die Inhalte zusammenführen?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Nein klicken, um stattdessen mit einem neuen Ordner zu synchronisieren</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Es konnte kein alternativer Ordnername gefunden werden</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Download konnte nicht eingerichtet werden:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Informationen zum Herunterladen der Paketquellen waren nicht abrufbar:
+Bitte %1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Bibliothek herunterladen</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>ändern …</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Passwort für diese Bibliothek:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Bearbeitungsdetails</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Neue Dateien</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Gelöschte Dateien</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Geänderte Dateien</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Neue Ordner</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Gelöschte Ordner</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Öffnen</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>&amp;Übergeordneten Ordner öffnen</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>%1-Dateibrowser</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Zurück</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Vorwärts</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Start</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Dateien hochladen</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Ordner hochladen</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Sie haben keine ausreichenden Rechte zum Hochladen in diese Bibliothek</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Neuer Ordner</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Aktualisieren</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 Objekte</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Name des Ordners</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Ungültiger Ordner-Name!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>Der Name „%1“ wird bereits benutzt.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>wiederholen</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Informationen zu Dateien waren nicht abrufbar.&lt;br/&gt;Bitte %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>Der Ordner ist leer.</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Speichern unter …</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Fehler beim Löschen der Datei „%1“</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Geben Sie den Pfad des gewünschten Speicherorts an …</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Möchten Sie die vorhandene Datei „%1“ wirklich ersetzen?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>Datei „%1“ ist nicht synchronisiert</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Die Datei %1 ist schon vorhanden.&lt;br/&gt;Möchten Sie die Datei wirklich überschreiben?&lt;br/&gt;&lt;small&gt;(Wählen Sie Nein, um die Datei mit einem anderen Namen hochzuladen).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Datei ist nicht vorhanden</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Fehler beim Herunterladen der Datei: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Datei zum Hochladen auswählen</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Wählen Sie einen Ordner zum Hochladen aus</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Umbennenen</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Möchten Sie die ausgewählten Objekte wirklich löschen?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Fehler beim Erstellen des Ordners</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Sperren fehlgeschlagen</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Datei zum Hochladen auswählen %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Umbenennen fehlgeschlagen</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Entfernen fehlgeschlagen</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Freigeben fehlgeschlagen</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Dateien aus dem selben Ordner können nicht eingefügt werden</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>Ordner können nicht in ihre Unterordner kopiert werden</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Kopieren fehlgeschlagen</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Verschieben fehlgeschlagen</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Das Erstellen der Bibliothek ist fehlgeschlagen!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Sie haben keine ausreichenden Rechte zum Hochladen in diesen Ordner</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Legitimierung abgelaufen</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Keine ausreichenden Rechte!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Bibliothek oder Ordner nicht gefunden</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation>Fehler beim Hochladen der Datei %1: %2</translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation>Cache-Ordner konnte nicht erstellt werden</translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation>Cache-Ordner konnte nicht geöffnet werden</translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Datei suchen</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Fehler beim Ermitteln des Links</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>In Vorbereitung</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbruch</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Hochladen</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Hochladevorgang %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Herunterladen</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Herunterladevorgang %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 von %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>Fehler beim Hochladen der Datei „%1“. Möchten Sie den Versuch wiederholen?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>Wiederholen</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Überspringen</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Abbrechen</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>Speichern …</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>Speichern der Datei fehlgeschlagen</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation>Fehler beim Indizieren des Fortschritts %1</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Name</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Größe</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Zuletzt geändert</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>Im Ordner &amp;ansehen</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Im Ordner ansehen</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Vorgang abgebrochen</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>ausführend</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>Aufgabe abgebrochen</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Interner Serverfehler</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Speicherplatz ist verbraucht</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>Gesperrt von %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Name</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Größe</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Zuletzt geändert</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation>Modifikator</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Speichern unter …</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Sperren</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Umbenennen</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Löschen</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Freigeben für Gruppe</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Aktualisieren</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Kopieren</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>&amp;Ausschneiden</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Einfügen</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>&amp;Herunterladen abbrechen.</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Diesen Ordner synchronisieren</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Dieses Feature ist nur in der Pro-Version verfügbar 
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>%1 &amp;Download-Link erstellen</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Freigeben für Nutzer/in</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>Internen Link erstellen</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Speichern unter …</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Ent&amp;sperren</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Schreibgeschützte Dateien können nicht gelöscht werden</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Schreibgeschützte Dateien können nicht ausgeschnitten werden</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>Hochladen wiederholen</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>Lokale Version löschen</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>Lokale Version speichern unter …</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation>Lokalen Zwischenspeicher öffnen</translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Fehler beim Ermitteln des Links</translation>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Fehler beim Erstellen der Ordner</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Fehler beim Erstellen der temporären Dateien</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Konnte Dateien nicht auf Laufwerk schreiben</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Fehler beim Entfernen der älteren Version der heruntergeladenen Datei</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Konnte Datei nicht verschieben</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 Initialisierung</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Einen %1-Ordner auswählen</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Bitte wählen Sie einen Ordner</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Initialisierung nicht abgeschlossen. Wirklich beenden?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Der Ordner %1 ist nicht vorhanden</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>Logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Ordner wählen</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Bitte wählen Sie einen Ort, an dem der Standard-Ordner von %1 erstellt werden soll. Wenn Sie künftig Bibliotheken herunterladen, ist dieser %1-Ordner als Ziel vorausgewählt.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Auswählen …</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Weiter</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1 organisiert Dateien in Bibliotheken.
+Möchten Sie Ihre Standardbibliothek herunterladen?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Standardbibliothek wird überprüft …</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Standardbibliothek wird erstellt …</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Fehler beim Erstellen der Standardbibliothek:
+
+Die Serverversion muss 2.1 oder höher sein, um dies zu unterstützen.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Fehler beim Herunterladen der Standardbibliothek:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Fehler beim Erstellen der Standardbibliothek:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Standardbibliothek wird heruntergeladen …</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Fehler beim Herunterladen der Standardbibliothek:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Die Standardbibliothek ist heruntergeladen.
+Klicken Sie auf „Öffnen“, um sie anzusehen.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Fehler beim Herunterladen der Standardbibliothek: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Fehler beim Herunterladen der Standardbibliothek:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1 organisiert Dateien in Bibliotheken.
+Möchten Sie Ihre Standardbibliothek herunterladen?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Überspringen</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Im Hintergrund laufen lassen</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Öffnen</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Abschließen</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Standardbibliothek herunterladen</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>Logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>mehr laden</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>Protokolldateien konnten nicht hochgeladen werden</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Protokolldateien werden hochgeladen</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Keine ausreichenden Rechte!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Bibliothek oder Ordner nicht gefunden</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Legitimierung abgelaufen</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>Protokolldateien konnten nicht hochgeladen werden: %1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>Protokolldateien sind hochgeladen</translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>Komprimieren der Daten</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 von %2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Konto hinzufügen</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>Single Sign-On</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Erneut anmelden</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Anmeldung wird durchgeführt …</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Netzwerkfehler:
+ %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Warnung:&lt;/b&gt; Das SSL-Zertifikat dieses Servers ist nicht vertrauenswürdig. Trotzdem fortfahren?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Bitte geben Sie die Serveradresse ein</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 ist keine gültige Serveradresse. Haben Sie „http(s)://“ vorangestellt?</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Bitte geben Sie den Benutzernamen ein</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Bitte geben Sie den Rechnernamen ein</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Aktuelles Konto konnte nicht gespeichert werden</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1-Serveradresse</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>Bitte geben Sie die Serveradresse ein</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1 ist keine gültige Serveradresse. Haben Sie „https://“ vorangestellt?</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Bitte geben Sie das Passwort ein</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>E-Mail-Adresse oder Passwort sind ungültig</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Zu viele Anmeldeversuche, bitte warten Sie eine Minute</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Interner Serverfehler</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Fehler beim Anmelden: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Fehler beim Anmelden</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>Logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Server:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Zum Beispiel: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>oder http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Passwort:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>Statustext</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Rechnername:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>E-Mail / Benutzername:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>z.B. Freyas Laptop</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Anmelden</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Automatisch anmelden</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Sie sind abgemeldet. Bitte </translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>Anmelden</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Ein Konto hinzufügen</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Ansicht aktualisieren</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation>„%1“ ist nicht synchronisiert. 
+Grund: Auf Server gelöscht</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation>„%1“ wurde synchronisiert</translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation>Dateien hochgeladen in „%1“</translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation>Konflikt mit Datei %1</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation>Datei %1 konnte nicht synchronisiert werden.
+Die Datei wird von einem anderen Programm verwendet. Die Datei wird aktualisiert, sobald Sie das Programm beenden.</translation>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation>Ordner %1 konnte nicht synchronisiert werden.
+Der Ordner wird von einem anderen Programm verwendet. Der Ordner wird aktualisiert, sobald Sie das Programm beenden.</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation>Datei %1 konnte nicht synchronisiert werden.
+Die Datei wurde von jemand anderem gesperrt. Ihre neue Version dieser Datei kann nicht hochgeladen werden.</translation>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation>Datei %1 konnte nicht indiziert werden.
+Bitte überprüfen Sie die Dateirechte und den freien Speicherplatz.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation>%1 konnte nicht synchronisiert werden.
+Der Dateipfad endet mit einem Leerschritt oder Punkt und kann auf Windows nicht erstellt werden.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation>%1 konnte nicht synchronisiert werden.
+Die Ordnerstruktur enthält ungültige Zeichen. Synchronisieren mit diesem Computer ist nicht möglich.</translation>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation>Die Datei %1 kann wegen der Rechteeinstellungen des Ordners nicht aktualisiert werden.</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation>„%1“ konnte nicht synchronisiert werden. 
+Zugriff auf Dienst verweigert</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation>„%1“ konnte nicht synchronisiert werden.
+Der Speicherplatz der Eigentümerin oder des Eigentümers der Bibliothek ist aufgebraucht.</translation>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Freigeben: %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Gruppenname eingeben</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Benutzernamen oder E-Mail-Adresse eingeben</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Aktualisiert</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>Freigabe fehlgeschlagen: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Entfernt</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Informationen zur Freigabe des Ordners nicht verfügbar</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Informationen zu Ihren Gruppen und Kontakten nicht verfügbar</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Bitte geben Sie den Benutzernamen ein</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Bitte geben Sie den Gruppennamen ein</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>Keine Gruppe gefunden mit Namen %1</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Bereits freigegeben für Gruppe %1</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Bereits freigegeben für Nutzer/in %1</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Der laufende Vorgang ist noch nicht abgeschlossen</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Freigeben für:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Freigeben</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Rechte:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Lesen + Schreiben</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Nur Lesen</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Schließen</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>synchronisiert</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indiziere Dateien</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>Synchronisieren initialisiert</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>herunterladen</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>hochladen</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>Zusammenfügen der Synchronisierung</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>auf Synchronisieren warten</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>Server nicht verbunden</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>Server-Legitimierung</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>Synchronisieren ist angehalten</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>unbekannt</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Server wurde entfernt</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Sie haben sich nicht am Server angemeldet</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Sie haben keine ausreichenden Rechte für den Zugriff auf diese Bibliothek</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Der Speicherplatz der Eigentümerin oder des Eigentümers der Bibliothek ist aufgebraucht</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Fernzugriff nicht verfügbar</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Zugriff auf Dienst verweigert</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Interne Daten beschädigt</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Fehler beim Starten des Hochladens</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Das Herunterladen konnte nicht gestartet werden</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Bibliothek auf dem Server ist beschädigt</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Konflikt beim Zusammenführen</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Serverversion ist zu alt</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Unbekannter Fehler</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Netzwerkfehler</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>Proxy-Adresse kann nicht aufgelöst werden</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>Serveradresse kann nicht aufgelöst werden</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>Kann nicht mit dem Server verbinden</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>Sichere Verbindung kann nicht hergestellt werden. Bitte überprüfen Sie das SSL-Zertifikat des Servers</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation>Die Datenübertragung wurde unterbrochen. Bitte überprüfen Sie das Netzwerk oder die Firewall</translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation>Die Datenübertragung wurde abgebrochen. Bitte überprüfen Sie das Netzwerk oder die Firewall</translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation>Der Server verwendet ein ungültiges „http redirect“. Bitte überprüfen Sie die Konfiguration des Server</translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Serverfehler</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Fehlerhafte Anforderung</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>Nicht genügend Arbeitsspeicher</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation>Das lokale Programm konnte keine Daten speichern. Bitte überprüfen Sie den freien Speicherplatz und die Schreibrechte in den Ordnern</translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>Kein Speicherplatz mehr</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>Bibliothek auf dem Server ist gelöscht</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>Bibliothek auf dem Server ist beschädigt</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Das Speicherkontingent wurde aufgebraucht</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Interner Serverfehler</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Ihr %1 Klient ist zu alt</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Fehler beim Synchronisieren dieser Bibliothek</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Dateien werden von einer anderen Anwendung verwendet</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Bibliothek auf dem Server ist gelöscht</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Fehler beim Zugriff auf den lokalen Ordner</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>Initialisierung läuft …</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>Fehler beim Indizieren lokaler Dateien</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>Server-Informationen konnten nicht überprüft werden</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>Fehler beim Erstellen lokaler Dateien</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>Fehler beim Zusammenfügen lokaler Dateiänderungen</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Falsches Passwort. Bitte noch einmal herunterladen</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Interner Fehler</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>Mit Server verbinden …</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>Dateien werden indiziert …</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Dateiliste wird geladen …</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Dateien werden geladen …</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Ordner wird erstellt …</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Dateiänderungen werden zusammengefügt …</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Fertig</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>Überprüfe die Server-Informationen …</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Abbrechen</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Abgebrochen</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL-Fehler</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Netzwerkfehler: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Serverfehler</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>Fehler beim Öffnen der Zertifikatsdatenbank</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>Datei „%1“ fehlt in „%2“</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 konnte keine Anwendung finden zum Öffnen von Datei %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Neue Bibliothek: %1</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Gelöschte Bibliothek „%1“</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>%1 umbenennen zu</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Fehler beim Herunterladen von „%1“</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>Fehler beim Kopieren</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Neu:</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Gelöscht:</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Entfernt</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Geändert:</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Umbenannt:</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Neu oder geändert:</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Verschoben:</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Neuer Ordner:</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Entfernter Ordner</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Umbenannter Ordner</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Verschobener Ordner</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>Dateien</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>Ordner</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>und noch %1</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Bibliothek zurückgesetzt zum Status von</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Datei „%1“ zurückgesetzt auf den Status von %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Gelöschter Ordner wiederhergestellt</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Bibliotheksname oder Beschreibung geändert</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>Automatische Zusammenführung durch %1</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>gerade eben</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>vor 1 Tag</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>vor %1 Tagen</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>vor 1 Stunde</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>vor %1 Stunden</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>vor 1 Minute</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>vor %1 Minuten</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Nicht Teil des Zertifikates&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Bibliothek hier als neuen Unterordner erstellen:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Ordner hier als neuen Unterordner erstellen:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Ordner</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Schreibgeschützter Ordner</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Dokument</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF-Dokument</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Bild</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Textdokument</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Audiodatei</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Videodatei</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Word-Dokument</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>PowerPoint-Dokument</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Excel-Dokument</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>Der Pfad „%1“ wird bereits vom System verwendet</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>Der Pfad „%1“ wird bereits von einer Bibliothek verwendet</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>Dateiliste wird hochgeladen</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>Datei wird von einer anderen Anwendung verwendet</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>Ordner wird von einer anderen Anwendung verwendet</translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>Datei wird von jemand anderem verwendet</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>Ungültiger Pfad</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Fehler beim Indizieren</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>Pfad endet mit einem Leerschritt oder Punkt</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>Pfad enthält ungültige Zeichen wie „|“ oder „:“</translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation>Fehler beim Öffnen der Datei-Cache Datenbank</translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation>Der Name der Bibliothek darf keine Zeichen wie „:“, „*“, „|“ oder „?“ enthalten</translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation>Die Datei kann wegen der Rechteeinstellungen des Ordners nicht aktualisiert werden </translation>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation>%1 läuft bereits</translation>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation>Fehler beim Hochladen</translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation>Fehler beim Herunterladen</translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation>Der Server hat den Zugang abgelehnt. Bitte versuchen Sie noch einmal, die Bibliothek zu synchronisieren</translation>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation>Bitte versuchen Sie, die Bibliothek neu zu synchronisieren. Es gibt einen Fehler bei der internen Datenverwaltung des lokalen Programms.</translation>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation>Keine Schreibrechte für die Bibliothek</translation>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation>Keine ausreichenden Rechte zum Synchronisieren der Bibliothek</translation>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation>Sie haben keine ausreichenden Rechte, um diesen Ordner zu synchronisieren</translation>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation>Alle Objekte aus dem Papierkorb entfernt</translation>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation>Objekte entfernt, die länger als %1 Tage im Papierkorb waren</translation>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation>Entwurf veröffentlicht</translation>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation>Entwurf erstellt</translation>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation>Datei erstellt</translation>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation>Datei umbenannt</translation>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation>Entwurf gelöscht</translation>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation>Datei gelöscht</translation>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation>Datei weiderhergestellt</translation>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation>Datei verschoben</translation>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation>Datei aktualisiert</translation>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation>Ordner erstellt</translation>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation>Ordner umbenannt</translation>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation>Ordner gelöscht</translation>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation>Ordner wiederhergestellt</translation>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation>Ordner verschoben</translation>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation>Bibliothek erstellt</translation>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation>Bibliothek umbenannt</translation>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation>Bibliothek gelöscht</translation>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation>Bibliothek wiederhergestellt</translation>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>Datei ist nicht vorhanden</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Bibliothek „%1“</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Diese Bibliothek wurde noch nicht heruntergeladen</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Fehler: </translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>alle %1 Sekunden</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Bibliothekssymbol</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>Bibliotheksname</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>TextLabel</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Eigentümer/in:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Zuletzt geändert:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Größe:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Lokaler Pfad:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Status:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Bibliotheksstatus</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Name:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Sync-Intervall:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Schließen</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>nicht heruntergeladen</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>Kann Datei „%1“ nicht öffnen, Bibliothek „%2“ nicht vorhanden</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Letzte Änderungen</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Meine Bibliotheken</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Unter-Bibliotheken</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Für mich freigegeben</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Für meine Abteilung</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Für meine Gruppen</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Synchronisierte Bibliotheken</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>Synchronisieren vorbereiten</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Synchronisieren aussetzen</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Synchronisieren fortsetzen</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>&amp;Details</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Details dieser Bibliothek anzeigen</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>Herunterladen und &amp;synchronisieren</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Herunterladen und synchronisieren</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Letzte Änderungen</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>&amp;Manuell synchronisieren</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Diese Bibliothek sofort synchronisieren</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>Herunterladen &amp;abbrechen</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Herunterladen dieser Bibliothek abbrechen</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>Im lokalen &amp;Ordner ansehen</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>Lokalen Ordner öffnen</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>Lokalen &amp;Ordner öffnen</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Synchronisieren trennen</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>Diese Bibliothek nicht mehr synchronisieren</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>Im Webbrowser ansehen</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>Diese Bibliothek auf Seahub ansehen</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Freigeben für Nutzer/in</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Bibliothek für Nutzer/in freigeben</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Freigeben für Gruppe</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Bibliothek für Gruppe freigeben</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>Im &amp;%1-Dateibrowser ansehen</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>Bibliothek im %1-Dateibrowser öffnen</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>&amp;Freigegebene Bibliothek verlassen</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>Freigegebene Bibliothek verlassen</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Neu synchronisieren</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>Synchronisieren trennen und erneut ausführen</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Sync-&amp;Intervall festlegen</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation>Sync-Intervall für diese Bibliothek festlegen</translation>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation>Soll die Bibliothek „%1“ wirklich nicht mehr synchronisiert werden?</translation>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation>Möchten Sie die Bibliothek „%1“ wirklich neu synchronisieren?</translation>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation>Möchten Sie die Datei „%1“ wirklich überschreiben?</translation>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Fehler beim Trennen des Synchronisierens der Bibliothek „%1“</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation>Möchten Sie „%1“ wirklich verlassen?</translation>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation>Die freigegebene Bibliothek konnte nicht verlassen werden</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Fehler beim Abbruch dieser Aufgabe:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Das Herunterladen wurde abgebrochen</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Sie haben keine ausreichenden Rechte zum Hochladen in diesen Ordner</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>Fehler beim Ersetzen der Datei „%1“</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Fehler beim Löschen der Datei „%1“</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Fehler beim Hochladen der Datei: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Sync-Intervall (in Sekunden):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Sync-Intervall für Bibliothek „%1“ festlegen</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>Bibliothek suchen</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>wiederholen</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Fehler beim Ermitteln der Bibliotheksinformationen.&lt;br/&gt;Bitte %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Warnung:&lt;/b&gt; Das SSL-Zertifikat dieses Servers ist nicht vertrauenswürdig. Trotzdem fortfahren?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>Standardkonto konnte nicht hingefügt werden</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Log konnte nicht initialisiert werden: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nein</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation>Fehler beim Speichern der ID des Programms</translation>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation>Fehler beim Zugriff auf %1</translation>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation>ID des Programms ist nicht richtig</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>Fehler beim Lesen von %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>%1-interner Link:</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Kopieren</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation>%1-interner Link:</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Unbekannter Fehler</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation>Interner Fehler: Verbindung zum Daemon-Hintergrundprogramm nicht möglich</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Synchronisieren aussetzen</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Synchronisieren fortsetzen</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Beenden</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Hauptfenster</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Einstellungen</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>%1-Ordner</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>öffne %1-Ordner</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>&amp;Protokollordner</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>Synchronisierungs-Fehler anzeigen</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Über</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Den „Über“-Dialog der Anwendung anzeigen</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;On­line­hil­fe</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Datei</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>Synchronisieren ist angehalten</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Wird hochgeladen</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Wird heruntergeladen</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>öffne %1-Protokollordner</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>öffne %1-Onlinehilfe</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>Einige Server nicht verbunden</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Protokolldaten hochladen</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>%1 Protokolldateien werden hochgeladen</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>Bitte melden Sie sich zuerst an</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation>Die Explorer-Erweiterung wiederherstellen</translation>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation>Icons im Explorer sind wiederhergestellt</translation>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation>Fehler beim Wiederherstellen der Icons im Explorer</translation>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>Im lokalen &amp;Ordner ansehen</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Im lokalen Ordner ansehen</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>Datei suchen</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>Neue Suche</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Suche fehlgeschlagen&lt;br /&gt;Bitte %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Verbindungsstatus der Server</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>verbunden</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>nicht verbunden</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Schließen</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Bitte geben Sie das Bibliothekspasswort ein</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>%1: Diese Bibliothek ist verschlüsselt. Bitte geben Sie das Passwort ein.</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Bitte geben Sie das Passwort ein</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Falsches Passwort</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Unbekannter Fehler</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Einstellungen</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>%1 nach der Anmeldung automatisch starten</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>%1-Icon aus dem Dock ausblenden</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Kein Proxy</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP-Proxy</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5-Proxy</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Proxy-Einstellungen des Systems</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Sie haben die Sprache geändert. Möchte Sie neustarten um die neue Sprache zu verwenden?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>Adresse des Proxy-Servers erforderlich</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>Port des Proxy-Servers ist fehlerhaft</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>Nutzername für den Proxy-Server erforderlich</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>Passwort für den Proxy-Server erforderlich</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Hauptfenster nach dem Start ausblenden</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Benachrichtigen, wenn Bibliotheken synchronisiert sind</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Temporäre Dateien von MS Office und LibreOffice synchronisieren</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Maximale Download-Geschwindigkeit (kB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Maximale Upload-Geschwindigkeit (kB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Allgemein</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Synchronisieren einer Bibliothek trotz lokalem Fehler nicht trennen</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Das Synchronisieren einer Bibliothek nicht automatisch trennen, wenn sie lokal nicht gefunden wird, z.B. weil sie verschoben oder umbenannt wurde.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Synchronisieren einer Bibliothek trotz Server-Fehler nicht trennen</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Das Synchronisieren einer Bibliothek nicht automatisch trennen, wenn sie auf dem Server nicht gefunden wird.</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Finder-Erweiterung aktivieren</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Die Explorer-Symbole anzeigen</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>Automatisch auf Aktualisierungen prüfen</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Server-Zertifikat bei https-Synchronisierung nicht überprüfen</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Synchronisieren von Ordnern mit unterschiedlichen Namen ermöglichen</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Erweitert</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Sprache (Neustart erforderlich):</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Sprache</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Proxy-Typ:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Host:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Port:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Benutzername:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Passwort:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Für den Proxy-Server ist ein Passwort erforderlich</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Netzwerk</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Lesen + Schreiben</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Nur Lesen</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Freigabe beenden</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>Zum Bearbeiten klicken</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Erstellt von %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Lesen + Schreiben</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Nur Lesen</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Gruppe</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Nutzer/in</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Rechte</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Der laufende Vorgang ist noch nicht abgeschlossen</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Freigabe-Link</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Freigabe-Link:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Direkt-Download</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Kopieren</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Nicht vertrauenswürdige Verbindung</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 benutzt ein nicht vertrauenswürdiges Sicherheitszertifikat. Die Verbindung ist möglicherweise nicht sicher. Trotzdem fortfahren?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Aktueller Fingerabdruck des RSA-Schlüssels ist %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Vorheriger Fingerabdruck des RSA-Schlüssels ist %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Meine Auswahl merken</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nein</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>Lokal &amp;öffnen</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Diese Datei öffnen</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>Im &amp;Webbrowser öffnen</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>Diese Datei auf der Website ansehen</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>wiederholen</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Informationen zu Favoriten konnten nicht geladen werden.&lt;br/&gt;Bitte %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Sie haben noch keine Dateien als Favoriten markiert..</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Fehler beim Synchronisieren</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>Keine Fehler beim Synchronisieren.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Doppelklick zum Öffnen der Bibliothek</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Bibliothek</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Pfad</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Fehler</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Zeit</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation>Geben Sie das Token der 2-Faktor-Authentifizierung ein</translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation>2-Faktor-Authentifizierung</translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation>Geben Sie das Token der 2-Faktor-Authentifizierung ein</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mSMS</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>Dieses Gerät merken</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Deinstallieren %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Möchten Sie die Kontoinformationen für %1 wirklich entfernen?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Kontoinformationen werden entfernt …</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>Text</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nein</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_el_GR.ts b/i18n/seafile_el_GR.ts
new file mode 100644 (file)
index 0000000..fbd382e
--- /dev/null
@@ -0,0 +1,3295 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="el_GR" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>Περί %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 πελάτης %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>Περί</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Έλεγχος για ενημερώσεις</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Εντάξει</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>αποτυχία ανοίγματος της βάσης δεδομένων του λογαριασμού</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Η πιστοποίηση έληξε, παρακαλούμε συνδεθείτε ξανά</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Ρυθμίσεις λογαριασμού</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Παρακαλούμε εισάγετε την διεύθυνση του διακομιστή</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 δεν είναι έγκυρη διεύθυνση διακομιστή</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Αποτυχία αποθήκευσης των πληροφοριών του λογαριασμού</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Αποτυχία αποθήκευσης των αλλαγών: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Η ενημέρωση των πληροφοριών του λογαριασμού εκτελέστηκε με επιτυχία</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Διεύθυνση διακομιστή</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Email</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Εντάξει</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Ακύρωση</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Αποτυχία αναίρεσης συγχρονισμού των βιβλιοθηκών του λογαριασμού:% 1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>κάντε κλικ για να ανοίξετε την ιστοσελίδα</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>έκδοση pro</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Κανένας λογαριασμός</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Επιλέξτε</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Ρυθμίσεις λογαριασμού</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Σύνδεση</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Διαγραφή</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Προσθήκη λογαριασμού</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Αποσύνδεση</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>δεν είστε συνδεδεμένος</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Φόρμα</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Λογαριασμός</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>email</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>διακομιστής</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Οι δραστηριότητες αρχείων υποστηρίζονται μόνο στην %1 επαγγελματική έκδοση διακομιστή.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>δοκιμάστε ξανά</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Αποτυχία λήψης των πληροφοριών δραστηριοτήτων. Παρακαλούμε% 1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Επιτυχία μεταφόρτωσης</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Το αρχείο &quot;%1&quot;
+μεταφορτώθηκε με επιτυχία.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Το αρχείο &quot;%1&quot;
+δεν μεταφορτώθηκε.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Αποτυχία δημιουργίας φακέλου avatar</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Άκυρο</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Λήψη εργασιών</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>απομάκρυνση των επιτυχημένων εργασιών</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Δεν υπάρχει λήψη εργασιών αυτή τη στιγμή.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Εκκαθάριση</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Κλείσιμο</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Βιβλιοθήκη</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Διαδρομή</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Ακύρωση της εργασίας</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>ακύρωση αυτής της εργασίας</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Αφαίρεση αυτής της εργασίας</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Αποτυχία ακύρωσης της εργασίας:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Αποτυχία αφαίρεσης της εργασίας:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Ελαχιστοποίηση</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Κλείσιμο</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Βιβλιοθήκες</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Με αστεράκι</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Δραστηριότητες</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Αναζήτηση</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>τρέχουσα ταχύτητα λήψης</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>τρέχουσα ταχύτητα μεταφόρτωσης</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Παρακαλούμε επιλέξτε ένα φάκελο για συγχρονισμό</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>κανένας συνδεδεμένος διακομιστής</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>όλοι οι διακομιστές είναι συνδεδεμένοι</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>μερικοί διακομιστές δεν είναι συνδεδεμένοι</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Φόρμα</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>λογότυπο</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>ελαχιστοποίηση</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>κλείσιμο</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Επιλέξτε</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>ή Αποθέστε φάκελο για Συγχρονισμό</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>ταχύτητα λήψης</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>κάτω βέλος</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>ταχύτητα μεταφόρτωσης</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>άνω βέλος</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Σφάλμα κατά την δημιουργία της ρυθμίσεων ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Αποτυχία δημιουργίας του προρυθμισμένου φακέλου &quot;%1¨&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>αδυναμία ανάγνωσης %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Δημιουργία βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Παρακαλούμε επιλέξτε έναν φάκελο</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Δημιουργία...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Αποτυχία δημιουργίας κρυπτογραφημένου κλειδιού για αυτή τη βιβλιοθήκη</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Παρακαλούμε επιλέξτε τον φάκελο που θέλετε να συγχρονίσετε</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Ο φάκελος %1 δεν υπάρχει</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Παρακαλούμε εισάγετε το όνομα</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Παρακαλούμε εισάγετε το συνθηματικό</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Τα συνθηματικά δεν ταιριάζουν</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Άγνωστο σφάλμα</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Αποτυχία προσθήκης διεργασίας λήψης:
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Αποτυχία δημιουργιας βιβλιοθήκης στον διακομιστή:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Διαδρομή:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Επιλέξτε</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Όνομα:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>κρυπτογραφημένο</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Συνθηματικό</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Επιβεβαίωση συνθηματικού:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>κείμενο κατάστασης</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Εντάξει</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Ακύρωση</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>%1 αποτυχία αρχικοποίησης πελάτη</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Παρακαλούμε εισάγετε το συνθηματικό</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Συγχρονισμός της βιβλιοθήκης &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Συγχρονισμός φακέλου &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Συγχρονισμός στον φάκελο:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>ή</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>συγχρονισμός με υπάρχων φάκελο</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>δημιουργία ενός νέου φακέλου συγχρονισμού</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Συγχρονισμός με αυτό τον υπάρχων φάκελο:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Παρακαλούμε επιλέξτε έναν φάκελο</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>Ο φάκελος δεν υπάρχει</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Παρακαλούμε επιλέξτε τον φάκελο που θα συγχρονιστεί.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Ο οργανισμός σας έχει απενεργοποιήσει την δυνατότητα τοποθέτησης μίας βιβλιοθήκης εκτός του φακέλου %1.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Υπάρχει διένεξη με το υπάρχον αρχείο &quot;%1&quot;¨, παρακαλούμε επιλέξτε διαφορετικό φάκελο.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Υπάρχει διένεξη με την υπάρχουσα βιβλιοθήκη &quot;%1&quot;, παρακαλούμε επιλέξτε ένα διαφορετικό φάκελο.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>Ο φάκελος &quot;%1&quot; υπάρχει ήδη. Είστε σίγουροι πως θέλετε να τον συγχρονίσετε (τα περιεχόμενα θα συγχωνευθούν);</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Κάντε κλικ στο Όχι για να συγχρονίσετε με ένα νέο φάκελο</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Αδυναμία εύρεσης εναλλακτικού ονόματος φακέλου</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Αποτυχία προσθήκης διεργασίας λήψης:
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Αποτυχία λήψης πληροφοριών λήψης repo:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Λήψη βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>επιλέξτε...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Κωδικός για αυτή τη βιβλιοθήκη:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ΟΚ</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Άκυρο</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Λεπτομέρειες τροποποίησης</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Αρχεία που προστέθηκαν</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>ΔΙεγραμμένα αρχεία</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Τροποποιημένα αρχεία</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Φάκελοι που προστέθηκαν</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Διεγραμμένοι φάκελοι</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Άνοιγμα</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Άνοιγμα &amp;γονικού φακέλου</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Εξερευνητής αρχείων cloud</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Πίσω</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Εμπρός</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Αρχική</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Μεταφόρτωση αρχείων</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Μεταφόρτωση φακέλου</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Δεν έχετε δικαιώματα μεταφόρτωσης αρχείων σε αυτή τη βιβλιοθήκη</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Δημιουργία φακέλου</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Ανανέωση</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Όνομα φακέλου</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Μη συμβατό όνομα φακέλου</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>Το όνομα &quot;%1&quot; χρησιμοποιείται ήδη.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>δοκιμάστε ξανά</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Αποτυχία λήψης πληροφοριών αρχείων&lt;br/&gt;Παρακαλώ %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>Αυτός ο φάκελος είναι κενός.</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Εισάγετε όνομα αρχείου για αποθήκευση</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Αποτυχία αφαίρεσης αρχείου &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Εισάγετε την διαδρομή του φακέλου στον οποίο θέλετε αν αποθηκεύσετε...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Θέλετε να αντικαθαστήσετε το υπάρχον αρχείο &quot;%1&quot;;</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>Το αρχείο &quot;%1&quot; δεν έχει συγχρονιστεί</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Το αρχείο %1 υπάρχει ήδη.&lt;br/&gt;Θέλετε να το αντικαταστήσετε;&lt;br/&gt;&lt;small&gt;(Επιλέξτε Όχι για να μεταφορτώσετε το αρχείο με διαφορετικό όνομα).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Αποτυχία λήψης του αρχείου: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Επιλέξτε ένα αρχείο για μεταφόρτωση</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Επιλέξτε ένα φάκελο για μεταφόρτωση</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Μετονομασία</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Θέλετε να διαγράψετε αυτή τα τα στοιχεία</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Αποτυχία δημιουργία φακέλου</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Το κλείδωμα του αρχείου απέτυχε</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Επιλέξτε ένα αρχείο για ενημέρωση %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Αποτυχία μετονομασίας</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Αποτυχία διαγραφής</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Αποτυχία κοινής χρήσης</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Δεν μπορείτε να επικολλήσετε αρχεία από τον ίδιο φάκελο</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Αποτυχία αντιγραφής</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Αποτυχία μετακίνησης</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Αποτυχία δημιουργίας βιβλιοθήκης!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Αναζήτηση αρχείων</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Άκυρο</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Μεταφόρτωση</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Μεταφορτώνεται %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Λήψη</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Λαμβάνεται %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 από %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Όνομα</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Μέγεθος</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Τελευταία τροποποίηση</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Η διεργασία ακυρώθηκε</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>σε εξέλιξη</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Εσωτερικό σφάλμα στον διακομιστή</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>κλειδώθηκε από %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Όνομα</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Μέγεθος</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Τελευταία τροποποίηση</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Αποθήκευση ως...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Κλείδωμα</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Μετονομασία</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Διαγραφή</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Διαμοιρασμός στην ομάδα</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Ενημέρωση</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Αντιγραφή</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Αποκ&amp;οπή</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Επικόλληση</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Ακύρω&amp;ση λήψης</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Συγχρονισμός αυτού του φακέλου</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Αυτή η δυνατότητα είνα διαθέσιμη στην έκδοση pro
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Διαμοιρασμός στον χρήστη</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Αποθήκευση ως σε...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Ξε&amp;κλείδωμα</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Αποτυχία αφαίρεσης αρχείων μόνο για ανάγνωση</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Αδυναμία αποκοπής αρχείων μόνο για ανάγνωση</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Αποτυχία δημιουργίας φακέλων</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Αποτυχία δημιουργίας προσωρινών αρχείων</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Αποτυχία εγγραφής του αρχείου στον δίσκο</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Αποτυχία διαγραφής παλιότερης έκδοσης του ληφθέντος αρχείου</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Αποτυχία μετακίνησης του αρχείου</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 Αρχικοποίηση</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Παρακαλώ επιλέξτε ένα φάκελο</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Η ενεργοποίηση δεν έχει τελείωσει. Θέλετε σίγουρα να σταματήσετε;</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Ο φάκελος %1 δεν υπάρχει</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>λογότυπο</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Επιλογή φακέλου</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Επιλέξτε...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Επόμενο</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Άκυρο</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Έλεγχος της προεπιλεγμένης βιβλιοθήκης σας...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Δημιουργία προεπιλεγμένης βιβλιοθήκης...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Αποτυχία δημιουργίας της προεπιλεγμένης ββλιοθήκης:
+
+Η έκδοση του δισκομιστή σας πρέπει να είνια 2.1 ή ανώτερη για να υποστηρίξει αυτό..</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Αποτυχία λήψης της προεπιλεγμένης βιβλιοθήκης:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Αποτυχία δημιουργίας της προεπιλεγμένης βιβλιοθήκης:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Γίνεται λήψη της προεπιλεγμένης βιβλιοθήκης...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Αποτυχία λήψης της προεπιλεγμένης βιβλιοθήκης:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Η προεπιλεγμένη βιβλιοθήκη έχει ληφθεί.
+Μπορείτε να κάνετε κλικ στο &quot;Άνοιγμα&quot; για να την προβάλετε.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Σφάλμα κατά την λήψη της προεπιλεγμένης βιβλιοθήκης: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Αποτυχία λήψης της προεπιλεγμένης βιβλιοθήκης:
+ %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Παράλειψη</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Εκτέλεση στο παρασκήνιο</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Άνοιγμα</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Ολοκλήρωση</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Λήψη προεπιλεγμένης βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ναι</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>λογότυπο</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>φόρτωση περισσοτέρων</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Ακύρωση</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 από %2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Προσθήκη λογαριασμού</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Επανασύνδεση</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Σύνδεση σε εξέλιξη...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Σφάλμα δικτύου: 
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Προσοχή:&lt;/b&gt; Το πιστοποιητικό ssl αυτού του διακομιστή δεν είναι έμπιστο, θέλετε να συνεχίσετε;</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Παρακαλώ εισάγετε την διεύθυνση του διακομιστή</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 δεν είναι έκγυρη διεύθυνση διακομιστή</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Παρακαλώ συμπληρώστε το όνομα χρήστη</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Παρακαλώ συμπληρώστε το όνομα του υπολογιστή</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Αποτυχία αποθήκευσης του λογαριασμού</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1 Διεύθυνση διακομιστή</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Παρακαλώ εισάγετε τον κωδικό πρόσβασης</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Λάθος email ή κωδικός πρόσβασης</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Πολύ συχνές συνδέσεις, παρακαλώ περιμένετε ένα λεπτό</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Εσωτερικό σφάλμα διακομιστή</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Αποτυχία σύνδεσης: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Αποτυχία σύνδεσης στον λογαριασμό</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>λογότυπο</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Διακομιστής:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Για παράδειγμα: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>ή http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Κωδικός πρόσβασης:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>κείμενο κατάστασης</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Όνομα υπολογιστή:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Email / Όνομα χρήστη:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>π.χ. Το laptop του Γιάννη</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Σύνδεση</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Άκυρο</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Αυτόματη είσοδος</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>¨Εχετε αποσυνδεθεί. Παρακαλώ</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>συνδεθείτε</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Προσθήκη λογαριασμού</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Ανανέωση</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Εισάγετε το όνομα της ομάδας</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Επιτυχημένη ενημέρωση</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Επιτυχημένη αφαίρεση</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Παρακαλούμε εισάγετε το όνομα χρήστη</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Παρακαλούμε εισάγετε το όνομα της ομάδας</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Διαμοιρασμός σε:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Διαμοιρασμός</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Δικαιώματα:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Ανάγνωση-Εγγραφή</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Μόνο ανάγνωση</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Κλείσιμο</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>συγχρονίστηκε</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>ευρετηρίαση αρχείων</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>αρχικοποίηση συγχρονισμού</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>λήψη</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>μεταφόρτωση</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>ο συγχρονισμός συγχωνεύει</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>αναμονή για συγχρονισμό</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>ο διακομιστής δεν είναι συνδεδεμένος</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>ο διακομιστής πιστοποιείται</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>ο αυτόματος συγχρονισμός είναι απενεργοποιημένος</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>άγνωστο</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Ο διακομιστής έχει αφαιρεθεί</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Δεν έχετε συνδεθεί στον διακομιστή</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Δεν έχετε δικαιώματα πρόσβασης για αυτή την βιβλιοθήκη</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Ο χώρος αποθήκευσης του ιδιοκτήτη της βιβλιοθήκης έχει χρησιμοποιηθεί</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Η απομακρυνσμένη υπηρεσία μη διαθέσιμη </translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Άρνηση πρόσβασης στην υπηρεσία</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Κατεστραμένα εσωτερικά δεδομένα</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Αποτυχία έναρξης μεταφόρτωσης</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Αποτυχία έναρξης λήψης</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Η βιβλιοθήκη περιέχει βλάβες στον διακομιστή</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Πρόωλημα κατά τη συγχώνευση</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Η έκδοση του διακομιστή είναι πολύ παλία</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Άγνωστο σφάλμα</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Σφάλμα δικτύου</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>Αδυναμία σύνδεσης στον διακομιστή</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Σφάλμα διακομιστή</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Το όριο χρήσης χώρου έχει χρησιμοποιηθεί</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Εσωτερικό σφάλμα διακομιστή</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Το %1 πρόγραμμα πελάτη σας είναι πολύ παλιό</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Αποτυχία συγχρονισμού της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Τα αρχεία είναι κλειδωμένα από κάποια άλλη εφαρμογή</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Η βιβλιοθήκη έχει διαγράφει από τον διακομιστή</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Σφάλμα κατά την πρόσβαση στον τοπικό φάκελο</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>αρχικοποίηση...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Εσφαλμένο συνθηματικό. Παρακαλούμε επαναλάβατε την λήψη</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Εσωτερικό σφάλμα</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>σύνδεση σε εξέλιξη..</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>Δημιουργία ευρετηρίου αρχείων</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Λήψη λίστας αρχείων...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Λήψη αρχείων...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Δημιουργία φακέλου...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Συγχώνευση αλλαγών αρχείων...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Ολοκληρώθηκε</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>έλεγχος πληροφοριών διακομιστή...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Ακύρωση σε εξέλιξη</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Ακυρώθηκε</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>σφάλμα SSL</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Σφάλμα δικτύου: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Σφάλμα διακομιστή</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>αποτυχία ανοίγματος βάσης δεδομένων πιστοποιητικών</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>Το αρχείο &quot;%1&quot; δεν υπάρχει στο &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>το &quot;%1&quot; δεν μπόρεσε να βρει εφαρμογή για να ανοίξει το αρχείο %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Η βιβλιοθήκη &quot;%1&quot; δημιουργήθηκε</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Η βιβλιοθήκη &quot;%1&quot; διαγράφηκε</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Μετονομασία %1 σε</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Αποτυχία λήψης του αντικειμένου &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>η αντιγραφή απέτυχε</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Προστέθηκε</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Διαγράφτηκε</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Αφαιρέθηκε</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Τροποποιήθηκε</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Μετονομάστηκε</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Προστέθηκε ή τροποποιήθηκε</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Μετακινήθηκε</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Προσθήκη φακέλου</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Αφαιρέθηκε ο φάκελος</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Μετονομάστηκε ο φάκελος</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Μετακινήθηκε ο φάκελος</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>αρχεία</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>φάκελοι</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>και %1 ακόμα</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Επαναφέρθηκε η βιβλιοθήκη στην κατάσταση στις</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Επαναφέρθηκε το αρχείο &quot;%1&quot; στην κατάσταση %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Ανακτήθηκε διεγραμένος φάκελος</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Αλλάχθηκε το όνομα της βιβλιοθήκης ή η περιγραφή</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Μόλις τώρα</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1 μέρα πριν</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 μέρες πριν</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1 ώρα πριν</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 ώρες πριν</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1 λεπτό πριν</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 λεπτά πριν</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Δεν είναι μέρος του πιστοποιητικού&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Συγχρονισμός αυτής της βιβλιοθήκης σε:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Συγχρονισμός αυτού του φακέλου σε:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Φάκελος</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Φάκελος μόνο για ανάγνωση</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Έγγραφο</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>Έγγραφο PDF</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Αρχείο εικόνας</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Έγγραφο κειμένου</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Αρχείο ήχου</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Αρχείο βίντεο</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Έγγραφο Word</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>Έγγραφο Powerpoint</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Έγγραφο Excel</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>μεταφόρτωση λίστας αρχείου</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>Το αρχείο είναι κλειδωμένο από άλλον χρήστη</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>Μη έγκυρη διαδρομή</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Σφάλμα κατά την καταλογοποίηση</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Βιβλιοθήκη &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Δεν έχει ληφθεί ακόμη αυτή η βιβλιοθήκη.</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Σφάλμα:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>RepoIcon</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>RepoName</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>TextLabel</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Κάτοχος:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Τελευταία τροποποίηση:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Μέγεθος:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Τοπική διαδρομή:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Κατάσταση:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>RepoStatus</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Όνομα:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Κλείσιμο</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Δεν έχει ληφθεί αυτή η βιβλιοθήκη.</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>Αποτυχία ανοίγματος αρχείου &quot;%1&quot; από την ανύπαρκτη βιβλιοθήκη &quot;%2&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Πρόσφατα ενημερωμένο</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Οι Βιβλιοθήκες μου</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Υποβιβλιοθήκες</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Διαμοιρασμένα με εμένα</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Διαμοιρασμένα με όλους</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Διαμοιρασμένα με ομάδες</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Συγχρονισμένες βιβλιοθήκες</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>αρχικοποίηση συγχρονισμού</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Απενεργοποίηση αυτόματου συγχρονισμού</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Ενεργοποίηση αυτόματου συγχρονισμού</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Προβολή &amp;λεπτομερειών</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Προβολή λεπτομερειών αυτής της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Συγχρονισμός αυτής της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Συγχρονισμός της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Πρόσφατες ενημερώσεις</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Συγχρονισμός &amp;τώρα</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Άμεσος συγχρονισμός της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Ακύρωση λήψης</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Ακύρωση λήψης αυτής της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Άνοιγμα φακέλου</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>άνοιγμα τοπικού φακέλου</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Αποσυγχρονισμός</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>αποσυχρονισμός αυτής της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Προβολή στο cloud</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>προβολή αυτής της βιβλιοθήκης στο seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Διαμοιρασμός με την χρήστη</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Διαμοιρασμός με την ομάδα</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Διαμοιρασμός της βιβλιοθήκης με την ομάδα</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Άνοιγμα του εξερευνητή αρχείων cloud</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>ανοίξτε αυτή τη βιβλιοθηκη με τον ενσωματωμένο εξερευνητή αρχείων Cloud</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>%Επανασυγχρονισμός αυτής της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>αποσυγχρόνισμός και επανασυγχρονισμός αυτής της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Αποτυχία αποσυγχρονισμού βιβλιοθήκης &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Αποτυχία ακύρωσης αυτής της εργασίας:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Η λήχη έχει ακυρωθεί</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>Αδυναμία αντικατάστασης αρχείου &quot;%1&quot; με τον εαυτό του</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Αδυναμία διαγραφής αρχείου &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Αδυναμία μεταφόρτωσης αρχείου: &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>δοκιμάστε ξανά</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Αποτυχία λήψης πληροφοριών βιβλιοθηκών &lt;br/&gt;Παρακαλώ %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Προσοχή:&lt;/b&gt; Το πιστοποιητικό ssl αυτού του διακομιστή δεν είναι έμπιστο, θέλετε να συνεχίσετε;</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>αποτυχία προσθήκης προεπιλεγμένου λογαριασμού</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Αποτυχία αρχικοποιήσης αρχείου καταγραφής: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Εντάξει</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ναι</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Όχι</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Ακύρωση</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Αντιγραφή στο πρόχειρο</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ΟΚ</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Άγνωστο σφάλμα</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Απενεργοποίηση αυτόματου συγχρονισμού</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Ενεργοποίηση αυτόματου συγχρονισμού</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Αποσύνδεση</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Προβολή κεντρικού παραθύρου</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Ρυθμίσεις</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Άνοιγμα %1 &amp;φακέλου</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>άνοιγμα %1 φακέλου</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Άνοιγμα φακέλου &amp;Καταγραφής</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Σχετικά</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Προβολή του κουτιού Σχετικά με την εφαρμογή</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Online βοήθεια</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Αρχείο</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>ο αυτόματος συγχρονισμός είναι απενεργοποιημένος</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Μεταφόρτωση</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Λήψη</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>άνοιγμα %1 φακέλου καταγραφής</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>άνοιγμα %1 online βοήθειας</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>κάποιοι διακομιστές δεν είναι συνδεδεμένοι</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Εμφάνιση στον φάκελο</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>δοκιμάστε ξανά</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Κατάσταση σύνδεσης διακομιστών</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>συνδεδεμένο</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>αποσυνδεδεμένο</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Κλείσιμο</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Παρακαλώ εισάγετε τον κωδικό πρόσβασης της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Εισάγετε τον κωδικό πρόσβασης για την βιβλιοθήκη %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Παρακαλώ εισάγεται τον κωδικό πρόσβασης</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Λάθος κωδικός πρόσβασης</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Άγνωστο σφάλμα</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ΟΚ</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Άκυρο</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Ρυθμίσεις</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Κανένα</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP Proxy</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5 Proxy</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Διαμεσολαβητής συστήματος</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Αλλάξατε την γλώσσα. Θέλετε να γίνει επανεκκίνηση για να εφαρμοστεί;</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>Η θύρα του διαμεσολαβητή είναι λανθασμένη</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Απόκρυψη του κεντρικού παραθύρου κατά την εκκίνηση</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Ειδοποίηση όταν συγχρονίζεται μια βιβλιοθήκη</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Ενεργόποιηση συγχρονισμού προσωρινών αρχείων του MSOffice/Libreoffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Όριο ταχύτητας λήψης (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Όριο ταχύτητας μεταφόρτωσης (kb/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Βασικό</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Να μην γίνετε αυτόματος αποσυγχρονισμός βιβλιοθηκών</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Να μην γίνετε αυτόματος αποσυγχρονισμός μίας βιβλιοθήκης όταν ο τοπικός φάκελος διαγραφεί ή είναι μη διαθέσιμος για άλλους λόγους.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Να μην γίνετε αποσυγχρονισμός μίας βιβλιοθήκης όταν δεν βρεθεί στον διακομιστή</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Να μην γίνετε αυτόματος αποσυγχρονισμός μίας βιβλιοθήκης όταν δεν βρεθεί στον διακομιστή</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Ενεργοποίηση της προσθήκης FinderSync</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Ενεργοποίηση προσθήκης Explorer</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Να μην γίνετε έλεγχος του πιστοποιητικού του διακομιστή κατά τον συγχρονισμό με HTTPS</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Ενεργοποίηση συγχρονισμού με υπάρχοντα φάκελο με διαφορετικό όνομα</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Προχωρημένες ρυθμίσεις</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Γλώσσα (απαιτείται επανεκκίνηση)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Γλώσσα</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Τύπος Proxy:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Διακομιστής:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Θύρα:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Όνομα χρήστη:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Κωδικός πρόσβασης:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Ο διακομιστής proxy απαιτεί κωδικό πρόσβασης</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Δίκτυο</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ΟΚ</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Άκυρο</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Ανάγνωση Εγγραφή</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Μόνο ανάγνωση</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Αφαίρεση κοινόχρηστου</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Ανάγνωση Εγγραφή</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Μόνο ανάγνωση</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Ομάδα</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Χρήστης</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Δικαιώματα</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Κοινή χρήση συνδέσμου</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Κοινή χρήση συνδέσμου:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Άμεση Λήψη</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Αντιγραφή στο πρόχειρο</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Μη έμπιστη σύνδεση</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>Ο %1 χρησιμοποιεί ένα μή έγκυρο πιστοποιητικό ασφαλείας. Η σύνδεση μπορεί να είναι μη ασφαλής. Θέλετε να συνεχίσετε;</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Το τωρινό RSA key ίχνος είναι %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Το προηγούμενο RSA key ίχνος είναι %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Απομνημόνευση της επιλογής μου</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ναι</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Όχι</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Άνοιγμα</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Άνοιγμα αυτού του αρχείου</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>προβολή στο &amp;Web</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>προβολή αυτού του αρχείου στην ιστοσελίδα</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>δοκιμάστε ξανά</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Αποτύχια λήψης πληροφορίων αρχείων με αστεράκι &lt;br/&gt; Παρακαλώ %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Δεν έχετε αρχεία σημειωμένα με αστεράκι ακόμη.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Σφάλματα συγχρονισμού αρχείου</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>Κανένα σφάλμα συγχρονισμού.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Κάντε διπλό κλικ για άνοιγμα της βιβλιοθήκης</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Βιβλιοθήκη</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Διαδρομή</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Σφάλμα</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Ώρα</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Απεγκατάσταση %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Δεν μπορείτε να αφαιρέσετε τις πληροφορίες λογαριασμού %1;</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Απομάκρυνση των πληροφοριών του λογαριασμού</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Παράθυρο</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>κείμενο</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ναι</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Όχι</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_en.ts b/i18n/seafile_en.ts
new file mode 100644 (file)
index 0000000..2cafa53
--- /dev/null
@@ -0,0 +1,3276 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="en_US">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+</TS>
diff --git a/i18n/seafile_es.ts b/i18n/seafile_es.ts
new file mode 100644 (file)
index 0000000..048fbc9
--- /dev/null
@@ -0,0 +1,3306 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="es" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>Acerca de %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 Cliente %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; REV %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>Acerca de</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Verificar si hay actualizaciones</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>fallo al abrir la base de datos de las cuentas</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>La autorización expiró, por favor ingrese nuevamente</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation>Fallo al eliminar identificador de sincronización de repositorio local: %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation>Fallo al obtener información de sincronización de repositorio del servidor: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Configuración de la Cuenta</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Dirección del servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 no es una dirección válida</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Fallo al guardar información de la cuenta</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Fallo al guardar los cambios: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Información de la cuenta  actualizada con éxito</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Dirección del Servidor</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Email</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>¿Está seguro que desea eliminar la cuenta %1?&lt;br&gt;&lt;br&gt;La cuenta será eliminada localmente. Toda información de sincronización también será eliminada. La cuenta en el servidor no se verá afectada. </translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Fallo al desincronizar bibliotecas de esta cuenta: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>click para abrir el sitio web</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>versión pro</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Sin cuenta</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Elegir</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Configuración de la cuenta</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Iniciar</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Eliminar</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Agregar una cuenta</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Desconectarse</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>no está conectado</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Form</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Cuenta</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>email</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>servidor</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Actividad de Archivos solamente en %1 Server Professional Edition.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Fallo al obtener información de actividades. Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Éxito al subir</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Archivo &quot;%1&quot;
+subido con éxito.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Archivo &quot;%1&quot;
+falló al subir.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Error de Permiso!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>La autorización expiró</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>El archivo no existe</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation>El archivo está bloqueado por %1, por favor intente más tarde</translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Fallo al subir: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Fallo al crear carpeta de avatares</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Comprobando Permiso</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Tareas de Descarga</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>eliminar tareas completas</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>No hay descargas ahora.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Limpiar</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Biblioteca</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Ruta</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Cancelar esta tarea</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>cancelar esta tarea</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Remover esta tarea</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Fallo al cancelar la tarea:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Fallo al eliminar esta tarea:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimizar</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Bibliotecas</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Favoritos</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Actividades</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Buscar</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>tasa actual de descarga</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>tasa actual de subida</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Elija una carpeta para sincronizar</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>sin servidor conectado</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>todos los servidores conectados</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>algunos servidores no conectados</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>De:</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimizar</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>cerrar</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Seleccione</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>brand</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>o arrastre la carpeta a sincronizar</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>tasa de descarga</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>bajar</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>tasa de subida</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>subir</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Error al crear la configuración ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>No se puede crear el directorio de preconfiguración &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>falla al leer %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Crear una biblioteca</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Elija una carpeta</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Creando...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Fallo al generar la clave de encriptación para esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Elija la carpeta para sincronizar</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>La carpeta %1 no existe</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Ingrese un nombre</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Defina una contraseña</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Las contraseñas no coinciden</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Fallo al agregar descarga:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Fallo al crear biblioteca en el servidor:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Ruta:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Elija</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nombre:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>encriptada</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contraseña:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Repetir Contraseña:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>estado actual</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>El cliente %1 no pudo inicializarse </translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>%1 terminó de forma inesperada</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Ingrese la contraseña</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Sincronizar biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Sincronizar carpeta &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Sincronizar con carpeta:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>o</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>sincronizar con una carpeta existente</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>crear una nueva carpeta para sincronizar</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Sincronizar con esta carpeta existente:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Por favor escoja una carpeta</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>La carpeta no existe</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Por favor escoja la carpeta a sincronizar.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Su organización no permite poner una biblioteca fuera de la carpeta %1.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflicto con el archivo existente &quot;%1&quot;, por favor escoja otra carpeta.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflicto con la biblioteca existente &quot;%1&quot;, por favor escoja otra carpeta.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>La carpeta &quot;%1&quot; ya existe. ¿Está seguro de sincronizar con esa carpeta? (los contenidos serán fusionados)</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Haga click en No para en lugar de eso sincronizar con una carpeta nueva</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>No se pudo encontrar un nombre de carpeta alternativo</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Fallo al agregar tarea de descarga:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Fallo al obtener información de descarga del repositorio:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Descargar Biblioteca</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>elija...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Contraseña para esta biblioteca:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Detalle de Modificaciones</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Archivos agregados</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Archivos eliminados</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Archivos modificados</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Carpetas agregadas</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Carpetas eliminadas</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Abrir</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Abrir carpeta s&amp;uperior</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Navegador de Archivos</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Atrás</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Adelante</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Inicio</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Subir archivos</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Subir una carpeta</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>No tiene permiso para subir archivos a esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Crear una carpeta</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Refrescar</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 items</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Nombre de carpeta</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>¡Nombre de carpeta inválido!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>El nombre &quot;%1&quot; ya está en uso.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Fallo al obtener información de archivos&lt;br/&gt;Por favor %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>La carpeta está vacía</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Ingrese el nombre del archivo a guardar...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>No se puede eliminar el archivo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Ingrese la ruta de la carpeta donde desea guardar...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>¿Desea sobreescribir el archivo &quot;%1&quot;  existente?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>El archivo &quot;%1&quot; no ha sido sincronizado</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>El archivo %1 ya existe.&lt;br/&gt;¿Desea reemplazarlo?&lt;br/&gt;&lt;small&gt;(Elija No para subirlo con un nombre alternativo).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>El archivo no existe</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Fallo al descargar el archivo: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Seleccione un archivo para subir</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Seleccione una carpeta a subir</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Renombrar</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>¿Realmente desea eliminar estos ítems?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Crear carpeta falló</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Bloquear archivo falló</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Seleccione un archivo para actualizar %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Renombrar falló</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Eliminar falló</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Compartir falló</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>No es posible pegar archivos en la misma carpeta</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>No es posible pegar la carpeta en una subcarpeta</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Copiar falló</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Mover falló</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Crear biblioteca falló!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>La autorización expiró</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Error de Permiso!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Biblioteca/Carpeta no encontrada.</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation>Fallo al subir el archivo %1: %2</translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation>No se puede crear carpeta de caché</translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation>No se puede abrir carpeta de caché</translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Buscar archivos</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Fallo al obtener enlace</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>Pendiente</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Subir</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Subiendo %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Descargar</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Descargando %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 de %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>Fallo al subir el archivo &quot;%1&quot;, ¿desea reintentar?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>Reintentar</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Saltear</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Abortar</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>Guardando</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>Guardar archivo falló</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation>Index progress request error %1</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Nombre</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Tamaño</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Última modifiación</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Mostrar en carpeta</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Mostrar en carpeta</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Operación cancelada</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>pendiente</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>tarea cancelada</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Error Interno del Servidor</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>bloqueado por %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Nombre</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Tamaño</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Modificado</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation>Modificador</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Guardar como...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Bloquear</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Renombrar</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Eliminar</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Compartir con un Grupo</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>Act&amp;ualizar</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Copiar</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Cor&amp;tar</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Pegar</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Ca&amp;ncelar Descarga</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Sincronizar esta carpeta</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Esta función sólo está disponible en la versión pro
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>&amp;Generar Enlace %1 para Descarga</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Compartir con un Usuario</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>G&amp;enerar Enlace Interno %1 </translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Guardar Como En...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Des&amp;bloquear</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>No se pueden eliminar archivos de sólo lectura</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>No se pueden cortar archivos de sólo lectura</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>Reintentar Subir</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>Eliminar versión local</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>Guardar versión local como...</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation>Abrir carpeta de caché local</translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Fallo al obtener enlace</translation>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Fallo al crear carpetas</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Fallo al crear archivos temporarios</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Fallo al escribir archivo en disco</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Fallo al eliminar la versión anterior del archivo descargado</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Fallo al mover archivo</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>Inicialización de %1</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Escoja carpeta %1</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Por favor elija una capeta</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Inicialización incompleta. ¿Seguro que desea salir?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>La carpeta %1 no existe</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Escoja una carpeta</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Por favor, escoja una carpeta. Se creará una subcarpeta %1 en ella. Esta carpeta será donde se guardarán las bibliotecas descargadas.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Elija...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Siguiente</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Verificando biblioteca predefinida...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Creando biblioteca predefinida...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Fallo al crear biblioteca predefinida
+
+La versión del servidor debe ser 2.1 o superior para esta función.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Fallo al obtener la biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Fallo al crear la biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Descargando biblioteca predefinida...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Fallo al descargar la biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Se descargó la biblioteca predefinida.
+Puede hacer click en &quot;Abrir&quot; para verla.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Error descargando biblioteca predefinida: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Fallo al descargar biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Saltear</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Ejecutar en segundo plano</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Abrir</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Finalizar</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Descargar biblioteca predefinida</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>cargar más</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>Subir archivos de registros falló</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Subir archivos de registros</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Error de permisos!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Biblioteca/Carpeta no encontrada.</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorización expiró</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>Subir arcchivos de registros falló: %1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>Archivos de registros subidos con éxito</translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>Comprimiendo</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 de %2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Agregar una cuenta</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>Single Sign On</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Re-conectar</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Iniciando sesión...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Error de red:
+ %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Aviso:&lt;/b&gt; el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Dirección del servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 no es una dirección válida</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Ingrese el nombre de usuario</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Ingrese el nombre del equipo</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Fallo al modificar la cuenta actual</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>Dirección del Servidor %1</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>La dirección del servidor no puede estar vacía</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1 no es una dirección válida para el servidor. Debe comenzar con &apos;https://&apos;</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Ingrese la contraseña</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Contraseña o correo incorrectos</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Demasiados intentos, por favor espere un minuto</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Error Interno del Servidor</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Fallo al iniciar sesión: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Fallo al iniciar sesión</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Servidor:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Por ejemplo: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>ó http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contraseña:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>estado actual</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Nombre de equipo:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Email / Usuario:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>p.ej. laptop de Juan</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Iniciar</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Ingreso automático</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Sesión cerrada. Por favor </translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>iniciar</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Agregar una cuenta</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Actualizar</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation>&quot;%1&quot; está desincronizada. 
+Motivo: Eliminada en el servidor</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation>&quot;%1&quot; está sincronizada</translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation>Archivos subidos a &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation>Conflicto en archivo %1</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otra aplicación. Será actualizado cuando cierre la aplicación.</translation>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation>Fallo al sincronizar la carpeta %1
+Algún archivo en esta carpeta está bloqueado por otra aplicación. Será actualizada cuando cierre la aplicación.</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otro usuario. Actualizaciones a este archivo no son subidas.</translation>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation>Failo al indexar el archivo %1
+Por favor verifique los permisos del archivo y el espacio en disco.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation>Fallo al sincronizar %1
+La ruta al archivo termina con un espacio o un punto y no puede ser creada en Windows.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation>Failo al sincronizar %1
+La ruta al archivo contiene caracteres invalidos. No se sincroniza a esta computadora.</translation>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation>Actualizaciones al archivo %1 son denegadas debido a los permisos de la carpeta.</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation>&quot;%1&quot; falló al sincronizar. 
+Acceso denegado al servicio</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation>&quot;%1&quot; falló al sincronizar
+El espacio de almacenamiento del propietario de la biblioteca está agotado.</translation>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Compartir %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Ingrese el nombre del grupo</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Ingrese el nombre de usuario o la dirección de correo electrónico</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Actualizado con éxito</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>La operación de comapartir falló: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Eliminado con éxito</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Fallo al obtener información de compartir de la carpeta</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Fallo al obtener la información de tus grupos y contactos</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Ingrese el nombre de usuario</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Ingrese el nombre del grupo</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>No existe el grupo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Ya has compartido con el grupo %1</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Ya has compartido con el usuario %1</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>La operación anterior todavía está en curso</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Compartir con:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Comaprtir</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Permiso:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Lectura-Escritura</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Sólo Lectura</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>sincronizada</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indexando archivos</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>iniciando sincronización</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>descargando</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>subiendo</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>sincronizando y fusionando</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>esperando sincronización</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>servidor no conectado</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>autenticando en servidor</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>sincronización automática desactivada</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>desconocido</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>El servidor fue removido</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>No ha iniciado sesión en el servidor</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>No tiene permiso para acceder a esta biblioteca</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>El espacio del dueño de la biblioteca ha sido utilizado en su totalidad</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Sevicio remoto no disponible</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Fallo al acceder al servicio</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Datos internos corruptos</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Fallo al iniciar subida</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Fallo al iniciar descarga</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>La biblioteca está dañada en el servidor</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Conflicto al unir</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>La versión del servidor es demasiado vieja</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Error de red</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>No se puede resolver la dirección del proxy</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>No se puede resolver la dirección del servidor</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>No se puede conectar al servidor</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>Fallo al intentar establecer una conexión segura. Por favor verifique el certificado SSL del servidor</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation>La transferencia de datos fue interrumpida. Por favor verifique la red o el firewall</translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation>Se acabó el tiempo de espera para la transferencia de datos. Por favor verifique la red o el firewall</translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation>Redireccionamiento http inesperado del servidor. Por favor verifique la configuración del servidor</translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Error del servidor</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Solicitud incorrecta</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>No hay suficiente memoria</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation>Fallo al escribir los datos en el cliente. Por favor verifique el espacio en disco y los permisos de las carpetas</translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>Espacio de almacenamiento completo</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>Biblioteca eliminada en el servidor</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>Biblioteca dañada en el servidor</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Error interno del servidor</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Su cliente %1 es demasiado viejo</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Fallo al sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Los archivos están bloqueados por otra aplicación</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>La biblioteca fue eliminada del servidor</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Error al acceder a la carpeta local</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>inicializando...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>Fallo al indexar archivos locales</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>Fallo al verificar la información del servidor</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>Fallo al crear archivos locales</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>Fallo agregar cambios en el archivo</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Contraseña incorrecta. Descargue de nuevo</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Error interno</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>conectando al servidor...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indexando archivos...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Descargando lista de archivos...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Descargando archivos...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Creando carpeta...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Agregando cambios en el archivo...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Listo</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>verificando informacion del servidor...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Cancelando</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Cancelado</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>Error SSL</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Error de red: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Error de servidor</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>fallo al abrir la base de datos de certificados</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>El archivo &quot;%1&quot; no existe en &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 no encontró una aplicación para abrir %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Biblioteca &quot;%1&quot; creada</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Biblioteca &quot;%1&quot; eliminada</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Renombrar %1 a</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>No es posible descargar el ítem &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>copiar falló</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Agregado</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Borrado</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Removido</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Modificado</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Renombrado</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Agregados o modificados</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Movido</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Carpeta agregada</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Carpeta removida</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Carpeta renombrada</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Carpeta movida</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>archivos</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>carpetas</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>y otros %1</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Biblioteca revertida al estado en</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Archivo &quot;%1&quot; revertido al estado en %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Carpeta borrada recuperada</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Nombre de biblioteca o descripción cambiados</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>Auto fusionado por el sistema %1</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Ahora</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>hace 1 día</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>hace %1 días</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>hace 1 hora</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>hace %1 horas</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>hace 1 minuto</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>hace %1 minutos</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;No es Parte del Certificado&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Sincronizar esta biblioteca con:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Sincronizar esta carpeta con:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Carpeta</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Carpeta de sólo lectura</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Documento</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>Documento PDF</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Archivo de Imagen</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Documento de Texto</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Archivo de Audio</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Archivo de Video</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Documento de Word</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>Documento de PowerPoint</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Documento de Excel</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>La ruta &quot;%1&quot; está en conflicto con una ruta del sistema</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>La ruta &quot;%1&quot; está en conflicto con una biblioteca existente</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>subiendo lista de archivos</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>El archivo está bloqueado por otra aplicación</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>La carpeta está bloqueada por otra aplicación</translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>El archivo está bloqueado por otro usuario</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>La ruta es inválida</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Error al indexar</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>La ruta finaliza con un punto o con un espacio</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>La ruta contiene caracteres inválidos como &apos;|&apos; or &apos;:&apos;</translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation>fallo al abrir el caché de la base de datos de archivos</translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation>El nombre de la biblioteca contiene caracteres inválidos, como  &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation>Actialización de archivo denegada debido a configuración de permisos de la carpeta</translation>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation>El cliente %1 ya se está ejecutando</translation>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation>Ocurrió un error en la subida</translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation>Ocurrió un error en la descarga</translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation>Permiso denegado en el servidor. Por favor intente resincronizar la biblioteca</translation>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation>Datos internos corruptos en el cliente. Por favor intente resincronizar la biblioteca</translation>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation>No tiene permiso de escritura en la biblioteca</translation>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation>No tiene permiso para sincronizar la biblioteca</translation>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation>No tiene permiso para sincronizar esta carpeta</translation>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation>Todos los items eliminados de la papelera </translation>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation>Todos los items con mas de %1 días eliminados de la papelera</translation>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation>Borrador publicado</translation>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation>Borrador creado</translation>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation>Archivo creado</translation>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation>Archivo renombrado</translation>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation>Borrador eliminado</translation>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation>Archivo eliminado</translation>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation>Archivo recuperado</translation>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation>Archivo movido</translation>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation>Archivo actualizado</translation>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation>Carpeta creada</translation>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation>Carpeta renombrada</translation>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation>Carpeta eliminada</translation>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation>Carpeta recuperada</translation>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation>Carpeta movida</translation>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation>Biblioteca creada</translation>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation>Biblioteca renombrada</translation>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation>Biblioteca eliminada</translation>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation>Biblioteca recuperada</translation>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>El archivo no existe</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Esta biblioteca aún no ha sido descargada</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Error:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>cada %1 segundos</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Icono del repositorio</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>NombreRepositorio</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Etiqueta</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Propietario:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Última modifiación:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Tamaño:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Ruta Local:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Estado:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Estado del Repositorio</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nombre:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Intervalo de Sincronización:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Esta biblioteca no ha sido descargada</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>No es posible abrir el archivo &quot;%1&quot; desde la biblioteca &quot;%2&quot;, que no existe</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Actualizado Recientemente</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Mis bibliotecas</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Sub Bibliotecas</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Compartido conmigo</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Compartido con todos</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Compartido con grupos</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Bibliotecas Sincronizadas</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>inicializando sincronización</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desactivar auto sincronización</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Activar auto sincronización</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Mostrar d&amp;etalles</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Mostrar detalles de esta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Actualizado Recientemente</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Sincronizar a&amp;hora</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Sincronizar biblioteca inmediatamente</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Cancelar descarga</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Cancelar descarga de la biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Abrir carpeta</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>abrir carpeta local</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>Abrir carpeta &amp;local</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Desincronizar</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>desincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Ver en la nube</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>ver esta biblioteca en la web</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Compartir con un usuario</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Compartir esta biblioteca con un usuario</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Compartir con un grupo</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Compartir esta biblioteca con un grupo</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Abrir navegador de archivos</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>abrir esta biblioteca en el navegador de archivos incorporado</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>A&amp;bandonar compartido</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>abandonar compartido</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Resincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>desincronizar y resincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Establecer &amp;Intervalo de sincronización</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation>establecer intervalo de sincronización para esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation>¿Seguro que desea desincronizar la biblioteca &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation>¿Seguro que desea resincronizar la biblioteca &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation>¿Está seguro de sobreescribir el archivo &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Fallo al desincronizar biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation>¿Seguro que desea abandonar el compartido &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation>Abandonar compartido falló</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Fallo al cancelar la tarea:
+
+.%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>La descarga fue cancelada</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>No es posible sobreescribir el archivo &quot;%1&quot; con él mismo</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>No se puede eliminar el archivo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Fallo al subir el archivo: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Intervalo de Sincronización (en segundos):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Establecer Intervalo de Sincronización para la Biblioteca &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>Buscar bibliotecas</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Fallo al obtener información de las bibliotecas&lt;br/&gt;Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>Aviso: el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>fallo al agregar la cuenta predefinida</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Fallo al crear registro: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation>fallo al guardar el id del cliente</translation>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation>fallo al acceder a %1</translation>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation>Id del cliente incorrecto</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>fallo al leer %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>Enlace Interno %1</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copiar al portapapeles</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation>Enlace interno %1:</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation>error interno: fallo al conectar con el servicio</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desactivar auto sincronización</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Activar auto sincronización</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Cerrar</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Ventana principal</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Configuración</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Abrir &amp;carpeta %1</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>abrir carpeta %1</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Abrir &amp;registros</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>Mostrar errores al sincronizar archivos</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>Acerca &amp;de</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Muestra la información de la aplicación</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Ayuda en línea</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Archivo</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>auto sincronización desactivada</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Subiendo</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Descargando</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>abrir registros %1</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>abrir ayuda en línea %1</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>algunos servidores no contectados</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Subir archivos de registros</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>subir %1 archivos de registros</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>Por favor, primero ingrese</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation>Reparar extensión explorer</translation>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation>Iconos de estado de sincronización para Explorer reparados con éxito</translation>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation>Fallo al reparar iconos de estado de sincronización para Explorer</translation>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Mostrar en carpeta</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Mostrar en carpeta</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>Buscar archivos</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Fallo al buscar&lt;br/&gt;Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Estado de conexión de servidores</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>conectado</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>desconectado</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Por favor suministre la contraseña para la biblioteca</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Suministre la contraseña para la biblioteca %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Ingrese la contraseña</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Contraseña incorrecta</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Configuración</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>Iniciar automáticamente %1 después del inicio de sesión</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>Ocultar el icono de %1 de la barra</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Ninguno</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>Proxy HTTP</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Proxy Socks5</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Proxy del Sistema</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Ha cambiado el idioma. ¿Desea reiniciar para aplicar el cambio?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>La dirección del proxy no puede estar vacía</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>El puerto del proxy es incorrecto</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>El nombre de usuario del proxy no puede estar vacío</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>La contraseña del proxy no puede estar vacía</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Ocultar ventana principal al iniciar</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Notificar al sincronizar bibliotecas</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Habilitar la sincronización de archivos temporarios de MSOffice/Libreoffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Límite de velocidad de descarga (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Límite de velocidad de subida (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Básico</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>No desincronizar automáticamente una biblioteca</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>No desincronizar automáticamente una biblioteca cuando la carpeta local haya sido removida o no esté accesible por otros motivos.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>No desincronizar una biblioteca cuando no se encuentre en el servidor</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>No desincronizar automáticamente una biblioteca cuando no se encuentre en el servidor</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Habilitar extensión FinderSync</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Habilitar extensión Explorer</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>Verificar si hay actualizaciones automáticamente</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>No verificar el certificado del servidor en sincronización HTTPS</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Habilitar sincronización con una carpeta existente con distinto nombre</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Avanzado</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Idioma (requiere reinicio)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Idioma</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Tipo de Proxy:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Dirección:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Puerto:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Usuario:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contraseña:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>El servidor proxy requiere una contraseña</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Red</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Lectura Escritura</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Sólo Lectura</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Eliminar Compartido</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>Click para editar</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Creado por %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Lectura Escritura</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Sólo Lectura</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Grupo</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Usuario</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Permiso</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>La operación anterior todavía está en curso</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Enlace para Compartir</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Enlace para compartir:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Descarga Directa</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copiar al portapapeles</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Conexión no confiable</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 utiliza un certificado de seguridad inválido. La conexión podría no ser segura. Desea continuar?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>La huella digital de la clave RSA actual es %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>La huella digital de la clave RSA anterior es %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Recordar mi elección</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Abrir</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Abrir este archivo</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>ver en la &amp;Web</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>ver este archivo en el sitio web</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Fallo al obtener información de archivos favoritos&lt;br/&gt;Por favor %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Aún no tiene archivos favoritos.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Errores al Sincronizar Archivos</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>No hay errores de sincronización</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Doble click para abrir la biblioteca</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Biblioteca</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Ruta</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Error</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Hora</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation>Ingrese el identificador de autenticación de dos factores</translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation>Auenticación de dos factores</translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation>Por favor ingrese el identificador de autenticación de dos factores</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mText</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>Recordar este dispositivo</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Desinstalar %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>¿Seguro que desea eliminar la información de la cuenta %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Eliminando información de la cuenta...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>texto</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_es_AR.ts b/i18n/seafile_es_AR.ts
new file mode 100644 (file)
index 0000000..63b6cc9
--- /dev/null
@@ -0,0 +1,3306 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_AR" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>Acerca de %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 Cliente %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; REV %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>Acerca de</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Verificar si hay actualizaciones</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>fallo al abrir la base de datos de las cuentas</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>La autorización expiró, por favor ingrese nuevamente</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation>Fallo al eliminar identificador de sincronización de repositorio local: %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation>Fallo al obtener información de sincronización de repositorio del servidor: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Configuración de la Cuenta</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Dirección del servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 no es una dirección válida</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Fallo al guardar información de la cuenta</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Fallo al guardar los cambios: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Información de la cuenta  actualizada con éxito</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Dirección del Servidor</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Email</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>¿Está seguro que desea eliminar la cuenta %1?&lt;br&gt;&lt;br&gt;La cuenta será eliminada localmente. Toda información de sincronización también será eliminada. La cuenta en el servidor no se verá afectada. </translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Fallo al desincronizar bibliotecas de esta cuenta: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>click para abrir el sitio web</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>versión pro</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Sin cuenta</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Elegir</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Configuración de la cuenta</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Iniciar</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Eliminar</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Agregar una cuenta</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Desconectarse</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>no está conectado</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Form</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Cuenta</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>email</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>servidor</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Actividad de Archivos solamente en %1 Server Professional Edition.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Fallo al obtener información de actividades. Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Éxito al subir</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Archivo &quot;%1&quot;
+subido con éxito.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Archivo &quot;%1&quot;
+falló al subir.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Error de Permiso!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>La autorización expiró</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>El archivo no existe</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation>El archivo está bloqueado por %1, por favor intente más tarde</translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Fallo al subir: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Fallo al crear carpeta de avatares</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Comprobando Permiso</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Tareas de Descarga</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>eliminar tareas completas</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>No hay descargas ahora.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Limpiar</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Biblioteca</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Ruta</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Cancelar esta tarea</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>cancelar esta tarea</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Remover esta tarea</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Fallo al cancelar la tarea:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Fallo al eliminar esta tarea:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimizar</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Bibliotecas</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Favoritos</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Actividades</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Buscar</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>tasa actual de descarga</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>tasa actual de subida</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Elija una carpeta para sincronizar</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>sin servidor conectado</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>todos los servidores conectados</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>algunos servidores no conectados</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>De:</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimizar</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>cerrar</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Seleccione</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>brand</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>o arrastre la carpeta a sincronizar</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>tasa de descarga</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>bajar</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>tasa de subida</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>subir</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Error al crear la configuración ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>No se puede crear el directorio de preconfiguración &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>falla al leer %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Crear una biblioteca</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Elija una carpeta</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Creando...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Fallo al generar la clave de encriptación para esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Elija la carpeta para sincronizar</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>La carpeta %1 no existe</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Ingrese un nombre</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Defina una contraseña</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Las contraseñas no coinciden</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Fallo al agregar descarga:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Fallo al crear biblioteca en el servidor:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Ruta:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Elija</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nombre:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>encriptada</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contraseña:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Repetir Contraseña:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>estado actual</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>El cliente %1 no pudo inicializarse </translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>%1 terminó de forma inesperada</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Ingrese la contraseña</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Sincronizar biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Sincronizar carpeta &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Sincronizar con carpeta:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>o</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>sincronizar con una carpeta existente</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>crear una nueva carpeta para sincronizar</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Sincronizar con esta carpeta existente:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Por favor escoja una carpeta</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>La carpeta no existe</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Por favor escoja la carpeta a sincronizar.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Su organización no permite poner una biblioteca fuera de la carpeta %1.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflicto con el archivo existente &quot;%1&quot;, por favor escoja otra carpeta.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflicto con la biblioteca existente &quot;%1&quot;, por favor escoja otra carpeta.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>La carpeta &quot;%1&quot; ya existe. ¿Está seguro de sincronizar con esa carpeta? (los contenidos serán fusionados)</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Haga click en No para en lugar de eso sincronizar con una carpeta nueva</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>No se pudo encontrar un nombre de carpeta alternativo</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Fallo al agregar tarea de descarga:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Fallo al obtener información de descarga del repositorio:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Descargar Biblioteca</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>elija...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Contraseña para esta biblioteca:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Detalle de Modificaciones</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Archivos agregados</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Archivos eliminados</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Archivos modificados</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Carpetas agregadas</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Carpetas eliminadas</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Abrir</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Abrir carpeta s&amp;uperior</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Navegador de Archivos</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Atrás</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Adelante</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Inicio</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Subir archivos</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Subir una carpeta</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>No tiene permiso para subir archivos a esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Crear una carpeta</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Refrescar</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 items</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Nombre de carpeta</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>¡Nombre de carpeta inválido!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>El nombre &quot;%1&quot; ya está en uso.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Fallo al obtener información de archivos&lt;br/&gt;Por favor %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>La carpeta está vacía</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Ingrese el nombre del archivo a guardar...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>No se puede eliminar el archivo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Ingrese la ruta de la carpeta donde desea guardar...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>¿Desea sobreescribir el archivo &quot;%1&quot;  existente?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>El archivo &quot;%1&quot; no ha sido sincronizado</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>El archivo %1 ya existe.&lt;br/&gt;¿Desea reemplazarlo?&lt;br/&gt;&lt;small&gt;(Elija No para subirlo con un nombre alternativo).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>El archivo no existe</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Fallo al descargar el archivo: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Seleccione un archivo para subir</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Seleccione una carpeta a subir</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Renombrar</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>¿Realmente desea eliminar estos ítems?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Crear carpeta falló</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Bloquear archivo falló</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Seleccione un archivo para actualizar %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Renombrar falló</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Eliminar falló</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Compartir falló</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>No es posible pegar archivos en la misma carpeta</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>No es posible pegar la carpeta en una subcarpeta</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Copiar falló</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Mover falló</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Crear biblioteca falló!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>La autorización expiró</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Error de Permiso!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Biblioteca/Carpeta no encontrada.</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation>Fallo al subir el archivo %1: %2</translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation>No se puede crear carpeta de caché</translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation>No se puede abrir carpeta de caché</translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Buscar archivos</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Fallo al obtener enlace</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>Pendiente</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Subir</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Subiendo %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Descargar</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Descargando %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 de %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>Fallo al subir el archivo &quot;%1&quot;, ¿desea reintentar?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>Reintentar</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Saltear</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Abortar</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>Guardando</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>Guardar archivo falló</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation>Index progress request error %1</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Nombre</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Tamaño</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Última modifiación</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Mostrar en carpeta</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Mostrar en carpeta</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Operación cancelada</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>pendiente</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>tarea cancelada</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Error Interno del Servidor</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>bloqueado por %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Nombre</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Tamaño</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Modificado</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation>Modificador</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Guardar como...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Bloquear</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Renombrar</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Eliminar</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Compartir con un Grupo</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>Act&amp;ualizar</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Copiar</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Cor&amp;tar</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Pegar</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Ca&amp;ncelar Descarga</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Sincronizar esta carpeta</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Esta función sólo está disponible en la versión pro
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>&amp;Generar Enlace %1 para Descarga</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Compartir con un Usuario</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>G&amp;enerar Enlace Interno %1 </translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Guardar Como En...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Des&amp;bloquear</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>No se pueden eliminar archivos de sólo lectura</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>No se pueden cortar archivos de sólo lectura</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>Reintentar Subir</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>Eliminar versión local</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>Guardar versión local como...</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation>Abrir carpeta de caché local</translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Fallo al obtener enlace</translation>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Fallo al crear carpetas</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Fallo al crear archivos temporarios</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Fallo al escribir archivo en disco</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Fallo al eliminar la versión anterior del archivo descargado</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Fallo al mover archivo</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>Inicialización de %1</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Escoja carpeta %1</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Por favor elija una capeta</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Inicialización incompleta. ¿Seguro que desea salir?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>La carpeta %1 no existe</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Escoja una carpeta</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Por favor, escoja una carpeta. Se creará una subcarpeta %1 en ella. Esta carpeta será donde se guardarán las bibliotecas descargadas.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Elija...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Siguiente</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Verificando biblioteca predefinida...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Creando biblioteca predefinida...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Fallo al crear biblioteca predefinida
+
+La versión del servidor debe ser 2.1 o superior para esta función.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Fallo al obtener la biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Fallo al crear la biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Descargando biblioteca predefinida...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Fallo al descargar la biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Se descargó la biblioteca predefinida.
+Puede hacer click en &quot;Abrir&quot; para verla.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Error descargando biblioteca predefinida: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Fallo al descargar biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Saltear</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Ejecutar en segundo plano</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Abrir</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Finalizar</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Descargar biblioteca predefinida</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>cargar más</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>Subir archivos de registros falló</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Subir archivos de registros</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Error de permisos!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Biblioteca/Carpeta no encontrada.</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorización expiró</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>Subir arcchivos de registros falló: %1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>Archivos de registros subidos con éxito</translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>Comprimiendo</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 de %2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Agregar una cuenta</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>Single Sign On</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Re-conectar</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Iniciando sesión...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Error de red:
+ %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Aviso:&lt;/b&gt; el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Dirección del servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 no es una dirección válida</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Ingrese el nombre de usuario</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Ingrese el nombre del equipo</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Fallo al modificar la cuenta actual</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>Dirección del Servidor %1</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>La dirección del servidor no puede estar vacía</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1 no es una dirección válida para el servidor. Debe comenzar con &apos;https://&apos;</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Ingrese la contraseña</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Contraseña o correo incorrectos</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Demasiados intentos, por favor espere un minuto</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Error Interno del Servidor</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Fallo al iniciar sesión: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Fallo al iniciar sesión</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Servidor:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Por ejemplo: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>ó http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contraseña:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>estado actual</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Nombre de equipo:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Email / Usuario:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>p.ej. laptop de Juan</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Iniciar</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Ingreso automático</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Sesión cerrada. Por favor </translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>iniciar</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Agregar una cuenta</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Actualizar</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation>&quot;%1&quot; está desincronizada. 
+Motivo: Eliminada en el servidor</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation>&quot;%1&quot; está sincronizada</translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation>Archivos subidos a &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation>Conflicto en archivo %1</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otra aplicación. Será actualizado cuando cierre la aplicación.</translation>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation>Fallo al sincronizar la carpeta %1
+Algún archivo en esta carpeta está bloqueado por otra aplicación. Será actualizada cuando cierre la aplicación.</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otro usuario. Actualizaciones a este archivo no son subidas.</translation>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation>Failo al indexar el archivo %1
+Por favor verifique los permisos del archivo y el espacio en disco.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation>Fallo al sincronizar %1
+La ruta al archivo termina con un espacio o un punto y no puede ser creada en Windows.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation>Failo al sincronizar %1
+La ruta al archivo contiene caracteres invalidos. No se sincroniza a esta computadora.</translation>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation>Actualizaciones al archivo %1 son denegadas debido a los permisos de la carpeta.</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation>&quot;%1&quot; falló al sincronizar. 
+Acceso denegado al servicio</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation>&quot;%1&quot; falló al sincronizar
+El espacio de almacenamiento del propietario de la biblioteca está agotado.</translation>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Compartir %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Ingrese el nombre del grupo</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Ingrese el nombre de usuario o la dirección de correo electrónico</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Actualizado con éxito</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>La operación de comapartir falló: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Eliminado con éxito</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Fallo al obtener información de compartir de la carpeta</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Fallo al obtener la información de tus grupos y contactos</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Ingrese el nombre de usuario</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Ingrese el nombre del grupo</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>No existe el grupo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Ya has compartido con el grupo %1</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Ya has compartido con el usuario %1</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>La operación anterior todavía está en curso</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Compartir con:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Comaprtir</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Permiso:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Lectura-Escritura</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Sólo Lectura</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>sincronizada</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indexando archivos</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>iniciando sincronización</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>descargando</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>subiendo</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>sincronizando y fusionando</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>esperando sincronización</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>servidor no conectado</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>autenticando en servidor</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>sincronización automática desactivada</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>desconocido</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>El servidor fue removido</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>No ha iniciado sesión en el servidor</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>No tiene permiso para acceder a esta biblioteca</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>El espacio del dueño de la biblioteca ha sido utilizado en su totalidad</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Sevicio remoto no disponible</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Fallo al acceder al servicio</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Datos internos corruptos</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Fallo al iniciar subida</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Fallo al iniciar descarga</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>La biblioteca está dañada en el servidor</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Conflicto al unir</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>La versión del servidor es demasiado vieja</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Error de red</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>No se puede resolver la dirección del proxy</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>No se puede resolver la dirección del servidor</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>No se puede conectar al servidor</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>Fallo al intentar establecer una conexión segura. Por favor verifique el certificado SSL del servidor</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation>La transferencia de datos fue interrumpida. Por favor verifique la red o el firewall</translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation>Se acabó el tiempo de espera para la transferencia de datos. Por favor verifique la red o el firewall</translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation>Redireccionamiento http inesperado del servidor. Por favor verifique la configuración del servidor</translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Error del servidor</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Solicitud incorrecta</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>No hay suficiente memoria</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation>Fallo al escribir los datos en el cliente. Por favor verifique el espacio en disco y los permisos de las carpetas</translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>Espacio de almacenamiento completo</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>Biblioteca eliminada en el servidor</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>Biblioteca dañada en el servidor</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Error interno del servidor</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Su cliente %1 es demasiado viejo</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Fallo al sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Los archivos están bloqueados por otra aplicación</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>La biblioteca fue eliminada del servidor</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Error al acceder a la carpeta local</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>inicializando...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>Fallo al indexar archivos locales</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>Fallo al verificar la información del servidor</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>Fallo al crear archivos locales</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>Fallo agregar cambios en el archivo</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Contraseña incorrecta. Descargue de nuevo</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Error interno</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>conectando al servidor...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indexando archivos...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Descargando lista de archivos...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Descargando archivos...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Creando carpeta...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Agregando cambios en el archivo...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Listo</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>verificando informacion del servidor...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Cancelando</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Cancelado</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>Error SSL</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Error de red: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Error de servidor</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>fallo al abrir la base de datos de certificados</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>El archivo &quot;%1&quot; no existe en &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 no encontró una aplicación para abrir %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Biblioteca &quot;%1&quot; creada</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Biblioteca &quot;%1&quot; eliminada</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Renombrar %1 a</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>No es posible descargar el ítem &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>copiar falló</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Agregado</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Borrado</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Removido</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Modificado</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Renombrado</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Agregados o modificados</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Movido</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Carpeta agregada</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Carpeta removida</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Carpeta renombrada</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Carpeta movida</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>archivos</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>carpetas</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>y otros %1</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Biblioteca revertida al estado en</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Archivo &quot;%1&quot; revertido al estado en %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Carpeta borrada recuperada</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Nombre de biblioteca o descripción cambiados</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>Auto fusionado por el sistema %1</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Ahora</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>hace 1 día</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>hace %1 días</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>hace 1 hora</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>hace %1 horas</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>hace 1 minuto</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>hace %1 minutos</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;No es Parte del Certificado&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Sincronizar esta biblioteca con:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Sincronizar esta carpeta con:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Carpeta</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Carpeta de sólo lectura</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Documento</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>Documento PDF</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Archivo de Imagen</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Documento de Texto</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Archivo de Audio</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Archivo de Video</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Documento de Word</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>Documento de PowerPoint</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Documento de Excel</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>La ruta &quot;%1&quot; está en conflicto con una ruta del sistema</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>La ruta &quot;%1&quot; está en conflicto con una biblioteca existente</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>subiendo lista de archivos</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>El archivo está bloqueado por otra aplicación</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>La carpeta está bloqueada por otra aplicación</translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>El archivo está bloqueado por otro usuario</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>La ruta es inválida</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Error al indexar</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>La ruta finaliza con un punto o con un espacio</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>La ruta contiene caracteres inválidos como &apos;|&apos; or &apos;:&apos;</translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation>fallo al abrir el caché de la base de datos de archivos</translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation>El nombre de la biblioteca contiene caracteres inválidos, como  &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation>Actialización de archivo denegada debido a configuración de permisos de la carpeta</translation>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation>El cliente %1 ya se está ejecutando</translation>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation>Ocurrió un error en la subida</translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation>Ocurrió un error en la descarga</translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation>Permiso denegado en el servidor. Por favor intente resincronizar la biblioteca</translation>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation>Datos internos corruptos en el cliente. Por favor intente resincronizar la biblioteca</translation>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation>No tiene permiso de escritura en la biblioteca</translation>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation>No tiene permiso para sincronizar la biblioteca</translation>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation>No tiene permiso para sincronizar esta carpeta</translation>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation>Todos los items eliminados de la papelera </translation>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation>Todos los items con mas de %1 días eliminados de la papelera</translation>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation>Borrador publicado</translation>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation>Borrador creado</translation>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation>Archivo creado</translation>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation>Archivo renombrado</translation>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation>Borrador eliminado</translation>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation>Archivo eliminado</translation>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation>Archivo recuperado</translation>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation>Archivo movido</translation>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation>Archivo actualizado</translation>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation>Carpeta creada</translation>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation>Carpeta renombrada</translation>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation>Carpeta eliminada</translation>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation>Carpeta recuperada</translation>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation>Carpeta movida</translation>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation>Biblioteca creada</translation>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation>Biblioteca renombrada</translation>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation>Biblioteca eliminada</translation>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation>Biblioteca recuperada</translation>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>El archivo no existe</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Esta biblioteca aún no ha sido descargada</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Error:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>cada %1 segundos</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Icono del repositorio</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>NombreRepositorio</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Etiqueta</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Propietario:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Última modifiación:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Tamaño:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Ruta Local:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Estado:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Estado del Repositorio</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nombre:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Intervalo de Sincronización:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Esta biblioteca no ha sido descargada</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>No es posible abrir el archivo &quot;%1&quot; desde la biblioteca &quot;%2&quot;, que no existe</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Actualizado Recientemente</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Mis bibliotecas</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Sub Bibliotecas</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Compartido conmigo</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Compartido con todos</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Compartido con grupos</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Bibliotecas Sincronizadas</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>inicializando sincronización</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desactivar auto sincronización</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Activar auto sincronización</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Mostrar d&amp;etalles</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Mostrar detalles de esta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Actualizado Recientemente</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Sincronizar a&amp;hora</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Sincronizar biblioteca inmediatamente</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Cancelar descarga</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Cancelar descarga de la biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Abrir carpeta</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>abrir carpeta local</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>Abrir carpeta &amp;local</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Desincronizar</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>desincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Ver en la nube</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>ver esta biblioteca en la web</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Compartir con un usuario</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Compartir esta biblioteca con un usuario</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Compartir con un grupo</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Compartir esta biblioteca con un grupo</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Abrir navegador de archivos</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>abrir esta biblioteca en el navegador de archivos incorporado</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>A&amp;bandonar compartido</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>abandonar compartido</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Resincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>desincronizar y resincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Establecer &amp;Intervalo de sincronización</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation>establecer intervalo de sincronización para esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation>¿Seguro que desea desincronizar la biblioteca &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation>¿Seguro que desea resincronizar la biblioteca &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation>¿Está seguro de sobreescribir el archivo &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Fallo al desincronizar biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation>¿Seguro que desea abandonar el compartido &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation>Abandonar compartido falló</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Fallo al cancelar la tarea:
+
+.%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>La descarga fue cancelada</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>No es posible sobreescribir el archivo &quot;%1&quot; con él mismo</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>No se puede eliminar el archivo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Fallo al subir el archivo: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Intervalo de Sincronización (en segundos):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Establecer Intervalo de Sincronización para la Biblioteca &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>Buscar bibliotecas</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Fallo al obtener información de las bibliotecas&lt;br/&gt;Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>Aviso: el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>fallo al agregar la cuenta predefinida</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Fallo al crear registro: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation>fallo al guardar el id del cliente</translation>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation>fallo al acceder a %1</translation>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation>Id del cliente incorrecto</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>fallo al leer %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>Enlace Interno %1</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copiar al portapapeles</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation>Enlace interno %1:</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation>error interno: fallo al conectar con el servicio</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desactivar auto sincronización</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Activar auto sincronización</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Cerrar</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Ventana principal</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Configuración</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Abrir &amp;carpeta %1</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>abrir carpeta %1</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Abrir &amp;registros</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>Mostrar errores al sincronizar archivos</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>Acerca &amp;de</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Muestra la información de la aplicación</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Ayuda en línea</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Archivo</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>auto sincronización desactivada</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Subiendo</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Descargando</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>abrir registros %1</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>abrir ayuda en línea %1</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>algunos servidores no contectados</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Subir archivos de registros</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>subir %1 archivos de registros</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>Por favor, primero ingrese</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation>Reparar extensión explorer</translation>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation>Iconos de estado de sincronización para Explorer reparados con éxito</translation>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation>Fallo al reparar iconos de estado de sincronización para Explorer</translation>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Mostrar en carpeta</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Mostrar en carpeta</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>Buscar archivos</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Fallo al buscar&lt;br/&gt;Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Estado de conexión de servidores</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>conectado</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>desconectado</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Por favor suministre la contraseña para la biblioteca</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Suministre la contraseña para la biblioteca %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Ingrese la contraseña</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Contraseña incorrecta</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Configuración</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>Iniciar automáticamente %1 después del inicio de sesión</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>Ocultar el icono de %1 de la barra</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Ninguno</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>Proxy HTTP</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Proxy Socks5</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Proxy del Sistema</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Ha cambiado el idioma. ¿Desea reiniciar para aplicar el cambio?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>La dirección del proxy no puede estar vacía</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>El puerto del proxy es incorrecto</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>El nombre de usuario del proxy no puede estar vacío</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>La contraseña del proxy no puede estar vacía</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Ocultar ventana principal al iniciar</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Notificar al sincronizar bibliotecas</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Habilitar la sincronización de archivos temporarios de MSOffice/Libreoffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Límite de velocidad de descarga (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Límite de velocidad de subida (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Básico</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>No desincronizar automáticamente una biblioteca</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>No desincronizar automáticamente una biblioteca cuando la carpeta local haya sido removida o no esté accesible por otros motivos.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>No desincronizar una biblioteca cuando no se encuentre en el servidor</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>No desincronizar automáticamente una biblioteca cuando no se encuentre en el servidor</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Habilitar extensión FinderSync</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Habilitar extensión Explorer</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>Verificar si hay actualizaciones automáticamente</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>No verificar el certificado del servidor en sincronización HTTPS</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Habilitar sincronización con una carpeta existente con distinto nombre</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Avanzado</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Idioma (requiere reinicio)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Idioma</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Tipo de Proxy:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Dirección:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Puerto:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Usuario:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contraseña:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>El servidor proxy requiere una contraseña</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Red</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Lectura Escritura</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Sólo Lectura</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Eliminar Compartido</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>Click para editar</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Creado por %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Lectura Escritura</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Sólo Lectura</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Grupo</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Usuario</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Permiso</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>La operación anterior todavía está en curso</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Enlace para Compartir</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Enlace para compartir:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Descarga Directa</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copiar al portapapeles</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Conexión no confiable</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 utiliza un certificado de seguridad inválido. La conexión podría no ser segura. Desea continuar?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>La huella digital de la clave RSA actual es %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>La huella digital de la clave RSA anterior es %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Recordar mi elección</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Abrir</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Abrir este archivo</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>ver en la &amp;Web</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>ver este archivo en el sitio web</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Fallo al obtener información de archivos favoritos&lt;br/&gt;Por favor %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Aún no tiene archivos favoritos.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Errores al Sincronizar Archivos</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>No hay errores de sincronización</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Doble click para abrir la biblioteca</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Biblioteca</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Ruta</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Error</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Hora</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation>Ingrese el identificador de autenticación de dos factores</translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation>Auenticación de dos factores</translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation>Por favor ingrese el identificador de autenticación de dos factores</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mText</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>Recordar este dispositivo</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Desinstalar %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>¿Seguro que desea eliminar la información de la cuenta %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Eliminando información de la cuenta...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>texto</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_es_MX.ts b/i18n/seafile_es_MX.ts
new file mode 100644 (file)
index 0000000..f485e83
--- /dev/null
@@ -0,0 +1,3306 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_MX" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>Acerca de %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 Cliente %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; REV %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>Acerca de</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Verificar si hay actualizaciones</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>fallo al abrir la base de datos de las cuentas</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>La autorización expiró, por favor ingrese nuevamente</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation>Fallo al eliminar identificador de sincronización de repositorio local: %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation>Fallo al obtener información de sincronización de repositorio del servidor: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Configuración de la Cuenta</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Dirección del servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 no es una dirección válida</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Fallo al guardar información de la cuenta</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Fallo al guardar los cambios: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Información de la cuenta  actualizada con éxito</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Dirección del Servidor</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Email</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>¿Está seguro que desea eliminar la cuenta %1?&lt;br&gt;&lt;br&gt;La cuenta será eliminada localmente. Toda información de sincronización también será eliminada. La cuenta en el servidor no se verá afectada. </translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Fallo al desincronizar bibliotecas de esta cuenta: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>click para abrir el sitio web</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>versión pro</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Sin cuenta</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Elegir</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Configuración de la cuenta</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Iniciar</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Eliminar</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Agregar una cuenta</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Desconectarse</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>no está conectado</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Form</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Cuenta</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>email</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>servidor</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Actividad de Archivos solamente en %1 Server Professional Edition.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Fallo al obtener información de actividades. Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Éxito al subir</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Archivo &quot;%1&quot;
+subido con éxito.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Archivo &quot;%1&quot;
+falló al subir.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Error de Permiso!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>La autorización expiró</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>El archivo no existe</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation>El archivo está bloqueado por %1, por favor intente más tarde</translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Fallo al subir: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Fallo al crear carpeta de avatares</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Comprobando Permiso</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Tareas de Descarga</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>Eliminar tareas completas</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>No hay descargas ahora.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Limpiar</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Biblioteca</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Ruta</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Cancelar esta tarea</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>cancela esta tarea</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Remover esta tarea</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Fallo al cancelar la tarea:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Fallo al eliminar esta tarea:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimizar</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Bibliotecas</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Favoritos</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Actividades</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Buscar</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>tasa actual de descarga</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>tasa actual de subida</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Elija una carpeta para sincronizar</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>sin servidor conectado</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>todos los servidores conectados</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>algunos servidores no conectados</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>De:</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimizar</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>cerrar</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Seleccione</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>brand</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>o arrastre la carpeta a sincronizar</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>tasa de descarga</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>bajar</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>tasa de subida</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>subir</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Error al crear la configuración ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>No se puede crear el directorio de preconfiguración &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>falla al leer %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Crear una biblioteca</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Escoja una carpeta</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Creando..</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Fallo al generar la clave de encriptación para esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Escoja directorio para sincronizar</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>La carpeta %1 no existe</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Ingrese un nombre</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Defina una contraseña</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Las contraseñas no coinciden</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Fallo al agregar descarga:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Fallo al crear biblioteca en el servidor:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Ruta:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Escoja</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nombre:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>encriptado</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contraseña:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Repetir Contraseña:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>estado actual</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>El cliente %1 no pudo inicializarse </translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>%1 terminó de forma inesperada</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Ingrese la contraseña</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Sincronizar biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Sincronizar carpeta &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Sincronizar con carpeta:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>o</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>sincronizar con una carpeta existente</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>crear una nueva carpeta para sincronizar</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Sincronizar con esta carpeta existente:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Por favor escoja una carpeta</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>La carpeta no existe</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Por favor escoja la carpeta a sincronizar.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Su organización no permite poner una biblioteca fuera de la carpeta %1.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflicto con el archivo existente &quot;%1&quot;, por favor escoja otra carpeta.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflicto con la biblioteca existente &quot;%1&quot;, por favor escoja otra carpeta.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>La carpeta &quot;%1&quot; ya existe. ¿Está seguro de sincronizar con esa carpeta? (los contenidos serán fusionados)</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Haga click en No para en lugar de eso sincronizar con una carpeta nueva</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>No se pudo encontrar un nombre de carpeta alternativo</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Fallo al agregar tarea de descarga:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Fallo al obtener información de descarga del repositorio:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Descargar Biblioteca</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>elija...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Contraseña para esta biblioteca:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Detalle de Modificaciones</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Archivos agregados</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Archivos eliminados</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Archivos modificados</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Carpetas agregadas</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Carpetas eliminadas</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Abrir</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Abrir carpeta s&amp;uperior</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Navegador de Archivos</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Atrás</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Adelante</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Inicio</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Subir archivos</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Subir una carpeta</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>No tiene permiso para subir archivos a esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Crear una carpeta</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Refrescar</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 items</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Nombre de carpeta</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>¡Nombre de carpeta inválido!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>El nombre &quot;%1&quot; ya está en uso.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Fallo al obtener información de archivos&lt;br/&gt;Por favor %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>La carpeta está vacía</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Ingrese el nombre del archivo a guardar...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>No se puede eliminar el archivo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Ingrese la ruta de la carpeta donde desea guardar...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>¿Desea sobreescribir el archivo &quot;%1&quot;  existente?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>El archivo &quot;%1&quot; no ha sido sincronizado</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>El archivo %1 ya existe.&lt;br/&gt;¿Desea reemplazarlo?&lt;br/&gt;&lt;small&gt;(Elija No para subirlo con un nombre alternativo).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>El archivo no existe</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Fallo al descargar el archivo: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Seleccione un archivo para subir</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Seleccione una carpeta a subir</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Renombrar</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>¿Realmente desea eliminar estos ítems?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Crear carpeta falló</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Bloquear archivo falló</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Seleccione un archivo para actualizar %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Renombrar falló</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Eliminar falló</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Compartir falló</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>No es posible pegar archivos en la misma carpeta</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>No es posible pegar la carpeta en una subcarpeta</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Copiar falló</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Mover falló</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Crear biblioteca falló!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>La autorización expiró</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Error de Permiso!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Biblioteca/Carpeta no encontrada.</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation>Fallo al subir el archivo %1: %2</translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation>No se puede crear carpeta de caché</translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation>No se puede abrir carpeta de caché</translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Buscar archivos</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Fallo al obtener enlace</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>Pendiente</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Subir</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Subiendo %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Descargar</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Descargando %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 de %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>Fallo al subir el archivo &quot;%1&quot;, ¿desea reintentar?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>Reintentar</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Saltear</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Abortar</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>Guardando</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>Guardar archivo falló</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation>Index progress request error %1</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Nombre</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Tamaño</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Última modifiación</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Mostrar en carpeta</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Mostrar en carpeta</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Operación cancelada</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>pendiente</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>tarea cancelada</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Error Interno del Servidor</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>bloqueado por %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Nombre</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Tamaño</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Modificado</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation>Modificador</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Guardar como...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Bloquear</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Renombrar</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Eliminar</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Compartir con un Grupo</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>Act&amp;ualizar</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Copiar</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Cor&amp;tar</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Pegar</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Ca&amp;ncelar Descarga</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Sincronizar esta carpeta</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Esta función sólo está disponible en la versión pro
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>&amp;Generar Enlace %1 para Descarga</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Compartir con un Usuario</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>G&amp;enerar Enlace Interno %1 </translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Guardar Como En...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Des&amp;bloquear</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>No se pueden eliminar archivos de sólo lectura</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>No se pueden cortar archivos de sólo lectura</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>Reintentar Subir</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>Eliminar versión local</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>Guardar versión local como...</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation>Abrir carpeta de caché local</translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Fallo al obtener enlace</translation>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Fallo al crear carpetas</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Fallo al crear archivos temporarios</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Fallo al escribir archivo en disco</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Fallo al eliminar la versión anterior del archivo descargado</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Fallo al mover archivo</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>Inicialización de %1</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Escoja carpeta %1</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Por favor elija una capeta</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Inicialización incompleta. ¿Seguro que desea salir?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>La carpeta %1 no existe</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Escoja una carpeta</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Por favor, escoja una carpeta. Se creará una subcarpeta %1 en ella. Esta carpeta será donde se guardarán las bibliotecas descargadas.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Elija...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Siguiente</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Verificando biblioteca predefinida...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Creando biblioteca predefinida...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Fallo al crear biblioteca predefinida
+
+La versión del servidor debe ser 2.1 o superior para esta función.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Fallo al obtener la biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Fallo al crear la biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Descargando biblioteca predefinida...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Fallo al descargar la biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Se descargó la biblioteca predefinida.
+Puede hacer click en &quot;Abrir&quot; para verla.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Error descargando biblioteca predefinida: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Fallo al descargar biblioteca predefinida:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Saltear</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Ejecutar en segundo plano</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Abrir</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Finalizar</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Descargar biblioteca predefinida</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>cargar más</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>Subir archivos de registros falló</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Subir archivos de registros</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Error de permisos!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Biblioteca/Carpeta no encontrada.</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorización expiró</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>Subir arcchivos de registros falló: %1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>Archivos de registros subidos con éxito</translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>Comprimiendo</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 de %2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Agregar una cuenta</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>Single Sign On</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Re-conectar</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Iniciando sesión...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Error de red:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Aviso:&lt;/b&gt; el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Dirección del servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 no es una dirección válida</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Ingrese el nombre de usuario</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Ingrese el nombre del equipo</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Fallo al modificar la cuenta actual</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>Dirección del Servidor %1</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>La dirección del servidor no puede estar vacía</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1 no es una dirección válida para el servidor. Debe comenzar con &apos;https://&apos;</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Ingrese la contraseña</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Contraseña o correo incorrectos</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Demasiados intentos, por favor espere un minuto</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Error Interno del Servidor</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Fallo al iniciar sesión: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Fallo al iniciar sesión</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Servidor:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Por ejemplo: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>ó http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contraseña:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>estado actual</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Nombre de equipo:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Email / Usuario:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>p.ej. laptop de Juan</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Iniciar</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Ingreso automático</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Sesión cerrada. Por favor </translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>iniciar</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Agregar una cuenta</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Actualizar</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation>&quot;%1&quot; está desincronizada. 
+Motivo: Eliminada en el servidor</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation>&quot;%1&quot; está sincronizada</translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation>Archivos subidos a &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation>Conflicto en archivo %1</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otra aplicación. Será actualizado cuando cierre la aplicación.</translation>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation>Fallo al sincronizar la carpeta %1
+Algún archivo en esta carpeta está bloqueado por otra aplicación. Será actualizada cuando cierre la aplicación.</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otro usuario. Actualizaciones a este archivo no son subidas.</translation>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation>Failo al indexar el archivo %1
+Por favor verifique los permisos del archivo y el espacio en disco.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation>Fallo al sincronizar %1
+La ruta al archivo termina con un espacio o un punto y no puede ser creada en Windows.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation>Failo al sincronizar %1
+La ruta al archivo contiene caracteres invalidos. No se sincroniza a esta computadora.</translation>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation>Actualizaciones al archivo %1 son denegadas debido a los permisos de la carpeta.</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation>&quot;%1&quot; falló al sincronizar. 
+Acceso denegado al servicio</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation>&quot;%1&quot; falló al sincronizar
+El espacio de almacenamiento del propietario de la biblioteca está agotado.</translation>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Compartir %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Ingrese el nombre del grupo</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Ingrese el nombre de usuario o la dirección de correo electrónico</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Actualizado con éxito</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>La operación de comapartir falló: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Eliminado con éxito</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Fallo al obtener información de compartir de la carpeta</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Fallo al obtener la información de tus grupos y contactos</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Ingrese el nombre de usuario</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Ingrese el nombre del grupo</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>No existe el grupo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Ya has compartido con el grupo %1</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Ya has compartido con el usuario %1</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>La operación anterior todavía está en curso</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Compartir con:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Comaprtir</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Permiso:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Lectura-Escritura</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Sólo Lectura</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>sincronizada</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indexando archivos</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>iniciando sincronización</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>descargando</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>subiendo</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>sincronizando y fusionando</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>esperando sincronización</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>servidor no conectado</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>autenticando en servidor</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>sincronización automática desactivada</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>desconocido</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>El servidor fue removido</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>No ha iniciado sesión en el servidor</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>No tiene permiso para acceder a esta biblioteca</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>El espacio del dueño de la biblioteca ha sido utilizado en su totalidad</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Sevicio remoto no disponible</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Fallo al acceder al servicio</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Datos internos corruptos</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Fallo al iniciar subida</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Fallo al iniciar descarga</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>La biblioteca está dañada en el servidor</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Conflicto al unir</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>La versión del servidor es demasiado vieja</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Error de red</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>No se puede resolver la dirección del proxy</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>No se puede resolver la dirección del servidor</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>No se puede conectar al servidor</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>Fallo al intentar establecer una conexión segura. Por favor verifique el certificado SSL del servidor</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation>La transferencia de datos fue interrumpida. Por favor verifique la red o el firewall</translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation>Se acabó el tiempo de espera para la transferencia de datos. Por favor verifique la red o el firewall</translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation>Redireccionamiento http inesperado del servidor. Por favor verifique la configuración del servidor</translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Error del servidor</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Solicitud incorrecta</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>No hay suficiente memoria</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation>Fallo al escribir los datos en el cliente. Por favor verifique el espacio en disco y los permisos de las carpetas</translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>Espacio de almacenamiento completo</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>Biblioteca eliminada en el servidor</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>Biblioteca dañada en el servidor</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Error interno del servidor</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Su cliente %1 es demasiado viejo</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Fallo al sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Los archivos están bloqueados por otra aplicación</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>La biblioteca fue eliminada del servidor</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Error al acceder a la carpeta local</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>inicializando...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>Fallo al indexar archivos locales</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>Fallo al verificar la información del servidor</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>Fallo al crear archivos locales</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>Fallo agregar cambios en el archivo</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Contraseña incorrecta. Descargue de nuevo</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Error interno</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>conectando al servidor...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indexando archivos...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Descargando lista de archivos...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Descargando archivos...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Creando carpeta...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Agregando cambios en el archivo...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Listo</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>verificando informacion del servidor...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Cancelando</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Cancelado</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>Error SSL</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Error de red: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Error de servidor</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>fallo al abrir la base de datos de certificados</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>El archivo &quot;%1&quot; no existe en &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 no encontró una aplicación para abrir %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Biblioteca &quot;%1&quot; creada</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Biblioteca &quot;%1&quot; eliminada</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Renombrar %1 a</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>No es posible descargar el ítem &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>copiar falló</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Agregado</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Borrado</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Removido</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Modificado</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Renombrado</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Agregados o modificados</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Movido</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Carpeta agregada</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Carpeta removida</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Carpeta renombrada</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Carpeta movida</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>archivos</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>carpetas</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>y otros %1</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Biblioteca revertida al estado en</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Archivo &quot;%1&quot; revertido al estado en %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Carpeta borrada recuperada</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Nombre de biblioteca o descripción cambiados</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>Auto fusionado por el sistema %1</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Ahora</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>hace 1 día</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>hace %1 días</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>hace 1 hora</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>hace %1 horas</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>hace 1 minuto</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>hace %1 minutos</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;No es Parte del Certificado&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Sincronizar esta biblioteca con:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Sincronizar esta carpeta con:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Carpeta</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Carpeta de sólo lectura</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Documento</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>Documento PDF</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Archivo de Imagen</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Documento de Texto</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Archivo de Audio</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Archivo de Video</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Documento de Word</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>Documento de PowerPoint</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Documento de Excel</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>La ruta &quot;%1&quot; está en conflicto con una ruta del sistema</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>La ruta &quot;%1&quot; está en conflicto con una biblioteca existente</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>subiendo lista de archivos</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>El archivo está bloqueado por otra aplicación</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>La carpeta está bloqueada por otra aplicación</translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>El archivo está bloqueado por otro usuario</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>La ruta es inválida</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Error al indexar</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>La ruta finaliza con un punto o con un espacio</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>La ruta contiene caracteres inválidos como &apos;|&apos; or &apos;:&apos;</translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation>fallo al abrir el caché de la base de datos de archivos</translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation>El nombre de la biblioteca contiene caracteres inválidos, como  &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation>Actialización de archivo denegada debido a configuración de permisos de la carpeta</translation>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation>El cliente %1 ya se está ejecutando</translation>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation>Ocurrió un error en la subida</translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation>Ocurrió un error en la descarga</translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation>Permiso denegado en el servidor. Por favor intente resincronizar la biblioteca</translation>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation>Datos internos corruptos en el cliente. Por favor intente resincronizar la biblioteca</translation>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation>No tiene permiso de escritura en la biblioteca</translation>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation>No tiene permiso para sincronizar la biblioteca</translation>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation>No tiene permiso para sincronizar esta carpeta</translation>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation>Todos los items eliminados de la papelera </translation>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation>Todos los items con mas de %1 días eliminados de la papelera</translation>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation>Borrador publicado</translation>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation>Borrador creado</translation>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation>Archivo creado</translation>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation>Archivo renombrado</translation>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation>Borrador eliminado</translation>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation>Archivo eliminado</translation>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation>Archivo recuperado</translation>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation>Archivo movido</translation>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation>Archivo actualizado</translation>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation>Carpeta creada</translation>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation>Carpeta renombrada</translation>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation>Carpeta eliminada</translation>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation>Carpeta recuperada</translation>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation>Carpeta movida</translation>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation>Biblioteca creada</translation>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation>Biblioteca renombrada</translation>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation>Biblioteca eliminada</translation>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation>Biblioteca recuperada</translation>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>El archivo no existe</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Esta biblioteca aún no ha sido descargada</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Error:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>cada %1 segundos</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Icono del repositorio</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>NombreRepositorio</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Etiqueta</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Propietario:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Última modifiación:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Tamaño:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Ruta Local:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Estado:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Estado del Repositorio</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nombre:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Intervalo de Sincronización:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Esta biblioteca no ha sido descargada</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>No es posible abrir el archivo &quot;%1&quot; desde la biblioteca &quot;%2&quot;, que no existe</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Actualizado Recientemente</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Mis bibliotecas</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Sub Bibliotecas</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Compartido conmigo</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Compartido con todos</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Compartido con grupos</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Bibliotecas Sincronizadas</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>inicializando sincronización</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desactivar auto sincronización</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Activar auto sincronización</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Mostrar d&amp;etalles</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Mostrar detalles de esta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Actualizado Recientemente</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Sincronizar a&amp;hora</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Sincronizar biblioteca inmediatamente</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Cancelar descarga</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Cancelar descarga de la biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Abrir carpeta</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>abrir carpeta local</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>Abrir carpeta &amp;local</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Desincronizar</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>desincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Ver en la nube</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>ver esta biblioteca en la web</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Compartir con un usuario</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Compartir esta biblioteca con un usuario</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Compartir con un grupo</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Compartir esta biblioteca con un grupo</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Abrir navegador de archivos</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>abrir esta biblioteca en el navegador de archivos incorporado</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>A&amp;bandonar compartido</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>abandonar compartido</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Resincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>desincronizar y resincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Establecer &amp;Intervalo de sincronización</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation>establecer intervalo de sincronización para esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation>¿Seguro que desea desincronizar la biblioteca &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation>¿Seguro que desea resincronizar la biblioteca &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation>¿Está seguro de sobreescribir el archivo &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Fallo al desincronizar biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation>¿Seguro que desea abandonar el compartido &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation>Abandonar compartido falló</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Fallo al cancelar la tarea:
+
+.%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>La descarga fue cancelada</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>No es posible sobreescribir el archivo &quot;%1&quot; con él mismo</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>No se puede eliminar el archivo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Fallo al subir el archivo: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Intervalo de Sincronización (en segundos):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Establecer Intervalo de Sincronización para la Biblioteca &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>Buscar bibliotecas</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Fallo al obtener información de las bibliotecas&lt;br/&gt;Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>Aviso: el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>fallo al agregar la cuenta predefinida</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Fallo al crear registro: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation>fallo al guardar el id del cliente</translation>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation>fallo al acceder a %1</translation>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation>Id del cliente incorrecto</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>fallo al leer %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>Enlace Interno %1</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copiar al portapapeles</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation>Enlace interno %1:</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation>error interno: fallo al conectar con el servicio</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desactivar auto sincronización</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Activar auto sincronización</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Cerrar</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Ventana principal</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Configuración</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Abrir &amp;carpeta %1</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>abrir carpeta %1</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Abrir &amp;registros</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>Mostrar errores al sincronizar archivos</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>Acerca &amp;de</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Muestra la información de la aplicación</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Ayuda en línea</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Archivo</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>auto sincronización desactivada</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Subiendo</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Descargando</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>abrir registros %1</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>abrir ayuda en línea %1</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>algunos servidores no contectados</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Subir archivos de registros</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>subir %1 archivos de registros</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>Por favor, primero ingrese</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation>Reparar extensión explorer</translation>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation>Iconos de estado de sincronización para Explorer reparados con éxito</translation>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation>Fallo al reparar iconos de estado de sincronización para Explorer</translation>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Mostrar en carpeta</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Mostrar en carpeta</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>Buscar archivos</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Fallo al buscar&lt;br/&gt;Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Estado de conexión de servidores</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>conectado</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>desconectado</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Cerrar</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Por favor suministre la contraseña para la biblioteca</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Suministre la contraseña para la biblioteca %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Ingrese la contraseña</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Contraseña incorrecta</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Error desconocido</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Configuración</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>Iniciar automáticamente %1 después del inicio de sesión</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>Ocultar el icono de %1 de la barra</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Ninguno</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>Proxy HTTP</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Proxy Socks5</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Proxy del Sistema</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Ha cambiado el idioma. ¿Desea reiniciar para aplicar el cambio?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>La dirección del proxy no puede estar vacía</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>El puerto del proxy es incorrecto</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>El nombre de usuario del proxy no puede estar vacío</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>La contraseña del proxy no puede estar vacía</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Ocultar ventana principal al iniciar</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Notificar al sincronizar bibliotecas</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Habilitar la sincronización de archivos temporarios de MSOffice/Libreoffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Límite de velocidad de descarga (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Límite de velocidad de subida (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Básico</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>No desincronizar automáticamente una biblioteca</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>No desincronizar automáticamente una biblioteca cuando la carpeta local haya sido removida o no esté accesible por otros motivos.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>No desincronizar una biblioteca cuando no se encuentre en el servidor</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>No desincronizar automáticamente una biblioteca cuando no se encuentre en el servidor</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Habilitar extensión FinderSync</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Habilitar extensión Explorer</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>Verificar si hay actualizaciones automáticamente</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>No verificar el certificado del servidor en sincronización HTTPS</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Habilitar sincronización con una carpeta existente con distinto nombre</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Avanzado</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Idioma (requiere reinicio)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Idioma</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Tipo de Proxy:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Dirección:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Puerto:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Usuario:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Contraseña:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>El servidor proxy requiere una contraseña</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Red</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Lectura Escritura</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Sólo Lectura</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Eliminar Compartido</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>Click para editar</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Creado por %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Lectura Escritura</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Sólo Lectura</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Grupo</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Usuario</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Permiso</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>La operación anterior todavía está en curso</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Enlace para Compartir</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Enlace para compartir:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Descarga Directa</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copiar al portapapeles</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Conexión no confiable</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 utiliza un certificado de seguridad inválido. La conexión podría no ser segura. Desea continuar?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>La huella digital de la clave RSA actual es %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>La huella digital de la clave RSA anterior es %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Recordar mi elección</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Abrir</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Abrir este archivo</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>ver en la &amp;Web</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>ver este archivo en el sitio web</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>reintentar</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Fallo al obtener información de archivos favoritos&lt;br/&gt;Por favor %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Aún no tiene archivos favoritos.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Errores al Sincronizar Archivos</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>No hay errores de sincronización</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Doble click para abrir la biblioteca</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Biblioteca</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Ruta</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Error</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Hora</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation>Ingrese el identificador de autenticación de dos factores</translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation>Auenticación de dos factores</translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation>Por favor ingrese el identificador de autenticación de dos factores</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mText</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>Recordar este dispositivo</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Desinstalar %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>¿Seguro que desea eliminar la información de la cuenta %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Eliminando información de la cuenta...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Detalles</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>texto</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_et_EE.ts b/i18n/seafile_et_EE.ts
new file mode 100644 (file)
index 0000000..211a5e9
--- /dev/null
@@ -0,0 +1,3274 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="et_EE" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>close</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>0</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_fr_FR.ts b/i18n/seafile_fr_FR.ts
new file mode 100644 (file)
index 0000000..b09a519
--- /dev/null
@@ -0,0 +1,3303 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="fr_FR" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>À propos %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; RÉV %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>À propos</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Vérification des mises à jour</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>Impossible d&apos;ouvrir la base de données des comptes</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Autorisation expirée, reconnectez-vous</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation>Impossible de supprimer les jetons de synchronisation des dépôts locaux : %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation>Impossible de synchroniser le dépôt depuis le serveur : %1</translation>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Paramètres du compte</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Entrez l&apos;adresse du serveur</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 n&apos;est pas une adresse de serveur valide</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Impossible de sauvegarder les informations du compte</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Impossible de sauvegarder les changements : %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Information du compte mise à jour avec succès</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Adresse du serveur</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>E-mail</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>Êtes-vous certain de vouloir supprimer le compte %1?&lt;br&gt;&lt;br&gt; Le compte sera supprimé localement. Toute la configuration de synchronisation sera également supprimée. Le compte sur le serveur ne sera pas affecté.</translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Impossible de désynchroniser les bibliothèques de ce compte:%1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>Cliquez pour ouvrir le site web</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>Version pro</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Pas de compte</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Sélectionner</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Paramètres du compte</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Connexion</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Supprimer</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Ajouter un compte</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Déconnexion</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>Non connecté</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulaire</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Compte</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>E-mail</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>Serveur</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Les activités sur les fichiers sont supportées uniquement dans la version professionnelle %1 .</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>Réessayer </translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Impossible de récupérer les informations des activités. Veuillez %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Envoyé avec succès</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Le fichier &quot;%1&quot;
+a été envoyé avec succès.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Le fichier &quot;%1&quot;
+n&apos;a pu être envoyé.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Erreur de permission !</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorisation expirée</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Le fichier n&apos;existe pas</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation>Le fichier est verrouillé par %1, veuillez réessayer plus tard</translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Échec de l&apos;envoi : %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Impossible de créer le dossier des avatars</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Vérification de permission</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Tâches de téléchargement</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>Supprimer toutes les tâches terminées avec succès</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Pas de tâches de téléchargement en cours.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Vider</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fermer</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Bibliothèque</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Répertoire</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Annuler cette tâche</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>Annuler cette tâche</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Supprimer cette tâche</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Impossible d&apos;annuler cette tâche :
+
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Impossible de supprimer cette tâche :
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Réduire</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fermer</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Bibliothèques</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Favoris</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Activités</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Rechercher</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>Vitesse actuelle de téléchargement</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>Vitesse actuelle d&apos;envoi</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Veuillez choisir un dossier à synchroniser</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>Aucun serveur connecté</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>Tous les serveurs sont connectés</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>Des serveurs ne sont pas connectés</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulaire</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>Réduire</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>Fermer</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Sélectionnez </translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>Marque</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>ou déposez un dossier à synchroniser</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>Vitesse de téléchargement</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>flèche du bas</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>Vitesse d&apos;envoi</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>flèche du haut</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Erreur lors de la création de la configuration de ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Impossible de créer la bibliothèque pré-configurée &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>impossible de lire %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Créer une bibliothèque</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Veuillez choisir un répertoire</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Création...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Impossible de générer une clé de cryptage pour cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Veuillez choisir le répertoire à synchroniser</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Le dossier %1 n&apos;existe pas</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Veuillez entrer un nom</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Veuillez entrer un mot de passe</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Les mots de passe ne correspondent pas</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Erreur inconnue</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Impossible d&apos;ajouter la tâche de téléchargement :
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Impossible de créer la bibliothèque sur le serveur :
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Répertoire :</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Choisir</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nom :</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>Chiffré</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Mot de passe :</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Vérification du mot de passe :</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>Texte d&apos;état</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>Le client %1 n&apos;a pas pu s&apos;initialiser</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>%1 a quitté de manière inattendue</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Veuillez entrer un mot de passe</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Synchroniser la bibliothèque &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Synchroniser le répertoire &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Synchroniser avec le dossier</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>ou</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>Synchroniser avec un dossier existant</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation> Créer un nouveau dossier à synchroniser</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Synchroniser avec un dossier existant :</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Choisissez un dossier</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>Le dossier n&apos;existe pas</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Choisissez le dossier à synchroniser.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Votre organisation a empêché l&apos;enregistrement d&apos;une bibliothèque en dehors du dossier %1.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflit avec le fichier existant &quot;%1&quot;, choisissez un dossier différent.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflit avec la bibliothèque existante &quot;%1&quot;, choisissez un dossier différent.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>Le dossier &quot;%1&quot; existe déjà. Êtes-vous certain de vouloir le synchroniser (son contenu sera fusionné)  ?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Cliquez sur Non pour synchroniser avec un nouveau dossier</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Impossible de trouver un autre nom de dossier</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Impossible d&apos;ajouter la tâche de téléchargement :
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Impossible de télécharger les informations du dépôt :
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Télécharger la bibliothèque</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>Choisir...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Mot de passe de cette bibliothèque :</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Détail des modifications</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Fichiers ajoutés</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Fichiers supprimés</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Fichiers modifiés</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Dossiers ajoutés</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Dossiers supprimés</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Ouvrir</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Ouvrir le dossier &amp;parent</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Navigateur de fichiers</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Retour</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Avancer</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Dossier personnel</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Envoyer des fichiers</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Envoyer un répertoire</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Vous n&apos;avez pas les droits pour envoyer des fichiers dans cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Créer un dossier</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Rafraichir</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 éléments</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Nom du dossier</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Nom de dossier invalide</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>Le nom &quot;%1&quot; est déjà utilisé.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>Réessayer </translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Impossible de récupérer les informations des fichiers &lt;br/&gt;Veuillez %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>Le dossier est vide.</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Entrer le nom du fichier à enregistrer...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Impossible d&apos;effacer le fichier &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Entrez le chemin du répertoire d&apos;enregistrement...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Voulez-vous écraser le fichier existant &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>Le fichier &quot;%1&quot; n&apos;a pas été synchronisé</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Le fichier %1 existe déjà.&lt;br/&gt;Voulez-vous le remplacer?&lt;br/&gt;&lt;small&gt;(Choisissez Non pour l&apos;enregistrer avec un autre nom).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Le fichier n&apos;existe pas</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Impossible de télécharger le fichier : %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Sélectionner un fichier à envoyer</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Sélectionner un répertoire à envoyer</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Renommer</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Voulez-vous vraiment supprimer ces éléments ?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Échec de la création du dossier</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Échec du verrouillage du fichier </translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Sélectionner un fichier à mettre à jour  %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Échec du renommage</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Échec d&apos;effacement</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Échec du partage</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Impossible de coller les fichiers d&apos;un même dossier</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>Ce dossier ne peut pas être collé dans son sous-dossier</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Échec de la copie</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Échec du déplacement</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Échec de création de la bibliothèque</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Vous n&apos;avez pas la permission d&apos;envoyer ce répertoire</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorisation expirée</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Erreur de permission !</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Bibliothèque/Répertoire non trouvé.</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation>Échec de l&apos;envoi du fichier %1 : %2</translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation>Impossible de créer le dossier de cache</translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation>Impossible d&apos;ouvrir le dossier de cache</translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Rechercher des fichiers</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Impossible d&apos;obtenir le lien</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>En attente</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Envoyer</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Envoi vers %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Télécharger</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Téléchargement de %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 sur %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>Échec de l&apos;envoi du fichier &quot;%1&quot;, voulez-vous réessayer ?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>Réessayer </translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Passer</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Annuler</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>Enregistrement</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>Échec de l&apos;enregistrement du fichier</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation>Erreur %1 de la requête de progression d&apos;index</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Nom</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Taille</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Dernière modification</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Afficher dans le dossier</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Afficher dans le dossier</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Opération annulée</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>En attente</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>Tâche annulée</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Erreur interne du serveur</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Le quota de stockage a été atteint</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>Verrouillé par %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Nom</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Taille</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Dernière modification</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation>Modificateur</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Enregistrer sous...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Verrouiller</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Renommer</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Supprimer</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Partager avec un groupe</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Mise à jour</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Copier</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Cou&amp;per</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Coller</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Annul&amp;er le téléchargement</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Synchroniser ce dossier</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Cette fonctionnalité est  disponible uniquement dans la version professionnelle
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>&amp;Générer un lien de téléchargement</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Partager avec un utilisateur</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>G&amp;énérer %1  lien interne</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Enregistrer sous...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Dé&amp;verrouiller</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Impossible de supprimer des fichiers en lecture seule</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Impossible de couper des fichiers en lecture seule</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>Réessayer l&apos;envoi</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>Supprimer la version locale</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>Enregistrer la version locale sous ...</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation>Ouvrir le dossier du cache local</translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Impossible d&apos;obtenir le lien</translation>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Impossible de créer des dossiers</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Impossible de créer des fichiers temporaires</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Impossible d&apos;écrire un fichier sur le disque</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Impossible de supprimer une ancienne version du fichier téléchargé</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Impossible de déplacer le fichier</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>Initialisation de %1</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Choisissez %1 dossier</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Veuillez choisir un répertoire</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>L&apos;initialisation n&apos;est pas terminée. Voulez-vous réellement quitter?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Le dossier %1 n&apos;existe pas</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>Logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Choisissez un dossier</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Veuillez choisir un dossier. Un %1 sous dossier y sera créé. Quand vous téléchargez une bibliothèque , elle y sera sauvegardée par défaut.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Choisir...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Suivant</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1 organise les fichiers par bibliothèques.
+Voulez-vous télécharger la bibliothèque par défaut ?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Vérification de votre bibliothèque par défaut...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Création de la bibliothèque par défaut</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Impossible de créer la bibliothèque par défaut :
+
+La version de votre serveur doit être 2.1 ou plus.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Impossible de récupérer la bibliothèque par défaut : 
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Impossible de créer la bibliothèque par défaut : 
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Téléchargement de la bibliothèque par défaut...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Impossible de télécharger la bibliothèque par défaut : 
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>La bibliothèque par défaut a été téléchargée.
+Vous pouvez cliquer sur le bouton &quot;Ouvrir&quot; pour la voir.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Erreur lors du téléchargement de la bibliothèque par défaut : %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Impossible de télécharger la bibliothèque par défaut :
+ %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1 organise les fichiers par bibliothèques.
+Voulez-vous télécharger la bibliothèque par défaut ?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Passer</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Lancer en arrière plan</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Ouvrir</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Terminer</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Télécharger la bibliothèque par défaut</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Oui</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>Charger plus</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>L&apos;envoi des fichiers log a échoué</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Envoi des fichiers log</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Erreur de permissions !</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Bibliothèque/Répertoire non trouvé.</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorisation expirée</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>L&apos;envoi des fichiers log a échoué : %1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>Envoi des fichiers log réussi</translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>Compression</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 sur %2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Ajouter un compte</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>Authentification unique</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Reconnexion</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Connexion...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Erreur réseau : %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Attention :&lt;/b&gt; Le certificat de sécurité de ce serveur n&apos;est pas approuvé, continuer quand même ?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Veuillez entrer l&apos;adresse du serveur</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 n&apos;est pas une adresse de serveur valide</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Veuillez entrer le nom d&apos;utilisateur</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Veuillez entrer le nom de l&apos;ordinateur</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Impossible d&apos;enregistrer le compte actuel</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1  adresse serveur</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>L&apos;adresse du serveur ne peut être vide</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1 n&apos;est pas une adresse de serveur valide. Cela doit commencer par &apos;https://&apos;</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Veuillez entrer le mot de passe</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>E-mail ou mot de passe incorrect</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Connexions trop fréquentes, veuillez attendre une minute</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Erreur interne du serveur</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Impossible de se connecter:%1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Impossible de se connecter</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Serveur :</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Par exemple : https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>ou http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Mot de passe :</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>Texte d&apos;état</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Nom de l&apos;ordinateur :</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>E-mail / Nom d&apos;utilisateur </translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>Par exemple : portable de Julien</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Connexion</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Connexion automatique</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Vous êtes déconnecté. S&apos;il vous plait</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>Connexion</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Ajouter un compte</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Rafraîchir</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation>&quot;%1&quot; in&apos;est pas synchronisé. 
+Raison  : supprimé du serveur</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation>&quot;%1&quot;est synchronisé</translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation>Fichiers chargés sur &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation>Fichier %1 en conflit</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation>Impossible de synchroniser le fichier %1
+Le fichier est verrouillé par une autre application. Ce fichier sera mis à jour lorsque vous aurez fermé l&apos;application.</translation>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation>Impossible de synchroniser le dossier %1
+Le dossier est verrouillé par une autre application. Ce dossier sera mis à jour lorsque vous aurez fermé l&apos;application.</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation>Impossible de synchroniser le fichier %1
+Le fichier est verrouillé par un autre utilisateur. La mise à jour de ce fichier n&apos;est pas chargée.</translation>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation>Impossible d&apos;indexer le fichier %1
+Veuillez vérifier les permissions sur le fichier et l&apos;espace disque.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation>Impossible de synchroniser %1
+Le fichier se termine par un espace ou un autre caractère invalide et ne peut pas être enregistré sur Windows</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation>Impossible de synchroniser %1
+Le nom de fichier contient des caractères invalides. Il n&apos;est pas synchronisé sur cet appareil.</translation>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation>La mise à jour de %1 est refusée par les paramètres de permissions du dossier.</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation>Échec de la synchronisation de %1. Accès refusé au service.</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation>Échec de la synchronisation de %1. L&apos;espace de stockage de l&apos;utilisateur est dépassé.</translation>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Partager %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Entrez le nom du groupe</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Entrez un nom d&apos;utilisateur ou une adresse e-mail</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Mise à jour réussie</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>Échec de l&apos;opération de partage : %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Suppression réussie</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Impossible d&apos;obtenir les informations de partage du dossier</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Impossible de récupérer vos informations de groupe et de contact</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Veuillez entrer le nom d&apos;utilisateur</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Veuillez entrez le nom du groupe</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>Groupe &quot;%1&quot; inexistant</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Déjà partagée avec le groupe %1</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Déjà partagée avec l&apos;utilisateur %1</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>L&apos;opération précédente est encore en cours</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Partager avec :</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Partager</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Droit d&apos;accès :</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Lecture-Écriture</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Lecture seule</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fermer</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>Synchronisé</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>Indexation des fichiers</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>Initialisation de la synchronisation</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>Téléchargement</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>Envoi</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>Fusion de la synchronisation</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>En attente de synchronisation</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>Serveur non connecté</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>Authentification du serveur</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>La synchronisation automatique est désactivée</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>Inconnu</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Le serveur a été supprimé</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Vous n&apos;êtes pas connecté au serveur</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Vous n&apos;avez pas l&apos;autorisation d&apos;accéder à cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>L&apos;espace de stockage du propriétaire de cette bibliothèque est plein</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Le service distant n&apos;est pas disponible</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Accès refusé au service.</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Donnée interne corrompue</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Erreur au démarrage de l&apos;envoi</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Échec au démarrage du téléchargement</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>La librairie est endommagée sur le serveur</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Conflit pendant la fusion</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>La version du serveur est trop ancienne</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Erreur inconnue</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Erreur réseau</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>L&apos;adresse du proxy ne peut être atteinte</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>L&apos;adresse du serveur ne peut être atteinte</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>Impossible de se connecter au serveur</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>Impossible d&apos;établir une connexion sécurisée. Veuillez vérifier votre certificat SSL</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation>Le transfert de données a été interrompu. Veuillez vérifier le connexion ou le pare-feu.</translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation>Le transfert des données a expiré. Veuillez vérifiez le réseau ou le pare-feu</translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation>Redirection HTTP non gérée depuis le serveur. Veuillez vérifier la configuration du serveur</translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Erreur serveur</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Mauvaise requête</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>Pas assez de mémoire</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation>Impossible d&apos;écrire les données sur le client. Veuillez vérifier l&apos;espace disque ou les permissions du dossier.</translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>Le quota de stockage est atteint</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>Bibliothèque supprimée sur le serveur</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>Bibliothèque endommagée sur le serveur</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Le quota de stockage est atteint</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Erreur interne du serveur</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Votre client %1 est trop ancien</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Échec de synchronisation de cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Les fichiers sont ouverts par une autre application</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>La bibliothèque a été supprimée sur le serveur</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Impossible d&apos;accéder au répertoire local</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>Initialisation...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>Impossible d’indexer les fichiers locaux</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>Impossible de vérifier les informations du serveur</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>Impossible de créer des fichiers locaux</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>impossible de fusionner des fichiers locaux</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Mot de passe incorrect. Veuillez le télécharger à nouveau</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Erreur interne</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>Connexion au serveur...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>Indexation des fichiers...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Téléchargement de la liste des fichiers en cours ...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Téléchargement des fichiers en cours ...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Création du dossier ...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Fusion des changements des fichiers...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Terminé</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>vérification des informations du serveur...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Annulation</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Annulé</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>Erreur SSL</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Erreur réseau : %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Erreur du serveur</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>Échec d&apos;ouverture de la base des certificats</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>Le fichier &quot;%1&quot; n&apos;existe pas dans &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 ne trouve pas d&apos;application pour ouvrir le fichier %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Bibliothèque &quot;%1&quot; créée</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Bibliothèque &quot;%1&quot; supprimée</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Renommer %1 en </translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Impossible de télécharger l&apos;objet &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>Échec de la copie</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Modification de</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Suppression de</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Suppression de</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Modification de</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Renommage de</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Ajouté ou modifié</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Déplacement de</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Répertoire ajouté</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Répertoire supprimé</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Répertoire renommé</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Répertoire déplacé</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>Fichiers</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>Répertoires</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>ainsi que %1</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Retour de la bibliothèque à l&apos;état du</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Retour du fichier %1 à l&apos;état du %2</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Restauration de la bibliothèque effacée</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Changement de nom ou de description de la bibliothèque</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>Fusion automatique par %1 système</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>À l&apos;instant</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>Il y a un jour</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>Il y a %1 jours</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>Il y a 1 heure</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>Il y a %1 heures</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>Il y a 1 minute</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>Il y a %1 minutes</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Not Part of Certificate&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Synchroniser cette bibliothèque avec :</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Synchroniser ce dossier avec :</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Dossier</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Dossier en lecture seule</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Document</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>Document PDF</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Fichier image</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Document texte</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Fichier audio</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Fichier vidéo</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Document Word</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>Document PowerPoint</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Document Excel</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>Le chemin &quot;%1&quot; est en conflit avec un chemin système</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>Le chemin &quot;%1&quot; est en conflit avec une bibliothèque existante</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>envoi de la liste des fichiers</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>Le fichier est verrouillé par une autre application</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>Le dossier est verrouillé par une autre application</translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>Le fichier est verrouillé par un autre utilisateur</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>Le chemin n&apos;est pas valide</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Erreur lors de l&apos;indexation</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>Le chemin se termine par un espace ou un caractère de période</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>Le chemin contient des caractères non valides comme &apos;|&apos; ou &apos;:&apos; </translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation>Échec de l&apos;ouverture du fichier cache de la base de données</translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation>La bibliothèque contient des caractères invalides comme &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation>La mise à jour du fichier est impossible à cause des paramètres de permission du dossier.</translation>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation>Le client %1 est déjà démarré.</translation>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation>Une erreur est apparue au chargement</translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation>Une erreur est apparue au téléchargement.</translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation>Permission au serveur refusée. Veuillez essayer de resynchroniser la bibliothèque</translation>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation>Données internes corrompues sur le client. Veuillez essayer de resynchroniser la bibliothèque</translation>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation>Vous n&apos;avez pas les droits pour écrire dans cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation>Vous n&apos;avez pas les droits pour synchroniser une bibliothèque</translation>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation>Vous n&apos;avez pas la permission de synchroniser ce dossier.</translation>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation>Suppression de tous les éléments de la corbeille</translation>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation>Suppression des éléments âgés de plus %1 jours de la corbeille</translation>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation>Brouillon publié</translation>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation>Brouillon créé</translation>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation>Fichier créé</translation>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation>Fichier renommé</translation>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation>Brouillon supprimé</translation>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation>Fichier supprimé</translation>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation>Fichier restauré</translation>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation>Fichier déplacé</translation>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation>Fichier mis à jour</translation>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation>Dossier créé</translation>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation>Dossier renommé</translation>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation>Dossier supprimé</translation>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation>Dossier restauré</translation>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation>Dossier déplacé</translation>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation>Bibliothèque créée</translation>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation>Bibliothèque renommée</translation>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation>Bibliothèque supprimée</translation>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation>Bibliothèque restaurée</translation>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>Le fichier n&apos;existe pas</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Bibliothèque &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Cette bibliothèque n&apos;a pas encore été téléchargée</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Erreur : </translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>Chaque %1 secondes</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>IcôneDépôt</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>NomDépôt</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>LabelTexte</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Propriétaire :</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Dernière  modification :</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Taille :</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Répertoire local :</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>État :</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>EtatDépôt</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nom :</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Intervalle de synchro : </translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fermer</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Cette bibliothèque n&apos;a pas été téléchargée</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>Impossible d&apos;ouvrir le fichier &quot;%1&quot; dans la bibliothèque inexistante &quot;%2&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Bibliothèques mises à jour récemment</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Mes bibliothèques</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Sous-bibliothèques</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Bibliothèques partagées avec moi</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Bibliothèques partagées avec tous</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Bibliothèques partagées avec des groupes</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Bibliothèques synchronisées</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>Initialisation de la synchronisation</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Désactiver la synchronisation automatique</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Activer la synchronisation automatique</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Afficher les &amp;détails</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Afficher les détails de cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Synchroniser cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Synchroniser cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Récemment envoyés</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Synchroniser &amp;maintenant</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Synchroniser cette bibliothèque immédiatement</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Annuler le téléchargement</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Annuler le téléchargement de cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Ouvrir le dossier</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>Ouvrir le dossier local</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>&amp;Ouvre un dossier local</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Désynchroniser</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>Désynchroniser cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>Voir dans le &amp;cloud</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>Voir cette bibliothèque sur Seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Partager avec l&apos;utilisateur</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Partager cette bibliothèque avec un utilisateur</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Partager avec un groupe</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Partager cette bibliothèque avec un groupe</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Ouvrir l&apos;explorateur de fichiers du cloud</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>Ouvrir cette bibliothèque dans l&apos;explorateur de fichiers du cloud</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>&amp;Quitter le partage</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>Quitter le partage</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Resynchroniser cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>Désynchroniser et resynchroniser cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Paramétrer l&apos;&amp;intervalle de synchro</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation>Paramétrer l&apos;intervalle de synchronisation pour cette bibliothèque</translation>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation>Êtes-vous certain de vouloir désynchroniser la bibliothèque &quot;%1&quot; ?</translation>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation>Êtes-vous certain de vouloir resynchroniser la bibliothèque &quot;%1&quot; ?</translation>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation>Êtes-vous certain de vouloir remplacer le fichier &quot;%1&quot; ?</translation>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Impossible de désynchroniser la bibliothèque &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation>Êtes-vous certain de vouloir quitter le partage &quot;%1&quot; ?</translation>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation>Échec d&apos;abandon du partage</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Impossible d&apos;annuler cette tâche :
+
+ %1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Le téléchargement a été annulé</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Vous n&apos;avez pas la permission d&apos;envoyer ce répertoire</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>Impossible d&apos;écraser le fichier %1 avec lui-même</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Impossible de supprimer le fichier &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Échec de l&apos;envoi du fichier : %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Intervalle de synchro (en secondes) :</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Paramétrer l&apos;intervalle de synchro pour la bibliothèque &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>Rechercher des bibliothèques</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>Réessayer </translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Impossible de récupérer les informations des bibliothèques&lt;br/&gt;Veuillez %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Attention :&lt;/b&gt; Le certificat de sécurité de ce serveur n&apos;est pas approuvé, continuer quand même ?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>Échec de l&apos;ajout du compte par défaut</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Échec de l&apos;initialisation du log: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Oui</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Non</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation>Impossible de sauvegarder l&apos;id du client.</translation>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation>Impossible d&apos;accéder à %1.</translation>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation>Id de client incorrect.</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>Impossible de lire %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>%1 lien interne</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copier dans le presse-papiers</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation>Lien interne %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Erreur Inconnue</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation>Erreur interne : impossible de se connecter au processus.</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Désactiver la synchronisation automatique</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Activer la synchronisation automatique</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Quitter</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Ouvrir la fenêtre principale</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Paramètres</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Ouvrir le &amp;dossier %1</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>Ouvrir le dossier %1</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Ouvrir le dossier &amp;logs</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>Ouvrir le log des erreurs de synchronisation</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;À propos</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Voir la boite de dialogue À propos</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>Aide en &amp;Ligne</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Fichier</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>La synchronisation automatique est désactivée</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Envoi en cours</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Téléhargement en cours</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>Ouvrir le dossier de log %1</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>Ouvrir l&apos;aide en ligne de %1</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>Des serveurs ne sont pas connectés</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Envoi des fichiers log</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>Envoi %1 des fichier de log</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>Veuillez vous connecter d&apos;abord</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation>Réparer l&apos;extension de l&apos;explorateur de fichiers</translation>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation>Succès de la réparation des icônes de statut de synchronisation de l&apos;extension de l&apos;explorateur de fichier</translation>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation>Echec de réparation des icônes de statut de synchronisation de l&apos;extension de l&apos;explorateur de fichier</translation>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Afficher dans le dossier</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Afficher dans le dossier</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>Recherche fichiers</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>Réessayer </translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Impossible de rechercher&lt;br/&gt;Veuillez %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>État de connexion des serveurs</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>Connecté</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>Déconnecté</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fermer</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Veuillez entrer le mot de passe de la bibliothèque</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Veuillez entrer le mot de passe de la bibliothèque %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Veuillez entrer le mot de passe</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Mot de passe incorrect</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Erreur inconnue</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Paramètres</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>Démarrer automatiquement %1 à l&apos;ouverture de session utilisateur</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>Masquer l&apos;icône de %1 de la barre</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Aucun</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>Proxy HTTP</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Proxy Socks5</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Utiliser les paramètres proxy du système</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Vous avez changé de langue, redémarrer pour appliquer ?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>L&apos;adresse du serveur proxy ne peut être vide</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>Le port proxy est erroné</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>Le nom d&apos;utilisateur du proxy ne peut être vide</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>Le mot de passe du proxy ne peut être vide</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Cacher la fenêtre principale au démarrage </translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Signaler lorsque les bibliothèques sont synchronisées</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Activer la synchronisation des fichiers temporaires MSOffice/LibreOffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Vitesse de téléchargement maximum (Ko/s) :</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Vitesse d&apos;envoi maximum (Ko/s) :</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Basique</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Ne pas désynchroniser automatiquement une bibliothèque</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Ne pas désynchroniser automatiquement une bibliothèque quand le dossier local est supprimé ou inaccessible pour d&apos;autres raisons</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Ne pas désynchroniser une bibliothèque non trouvée sur le serveur</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Ne pas désynchroniser automatiquement une bibliothèque quand elle n&apos;est pas trouvée sur le serveur</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Activer l&apos;extension FinderSync</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Activer l&apos;extension de l&apos;explorateur de fichiers</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>Vérifier les mises à jour automatiquement</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Ne pas vérifier le certificat serveur lors de la connexion HTTPS</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Autoriser la synchronisation avec un dossier portant un nom différent</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Avancé</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Langue (redémarrage nécessaire)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Langue</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Type de proxy :</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Serveur :</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Port :</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Identifiant :</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Mot de passe :</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Le serveur proxy requiert un mot de passe</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Réseau</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Lecture et Écriture</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Lecture seule</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Supprimer le partage</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>Cliquez pour éditer</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Créée par %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Lecture Écriture</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Lecture seule</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Groupe</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Utilisateur</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Droit d&apos;accès</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>L&apos;opération précédente est toujours en cours</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Lien de partage</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Lien de partage :</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Téléchargement direct</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copier dans le presse-papiers</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Connexion non certifiée</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 utilise un certificat de sécurité invalide. La connexion peut ne pas être sécurisée. Voulez-vous continuer ?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>L&apos;empreinte courante de la clé RSA est %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>L&apos;empreinte précédente de la clé RSA est %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Se souvenir de mon choix</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Oui</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Non</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Ouvrir</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Ouvrir ce fichier</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>Voir sur &amp;Internet</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>Voir ce fichier sur le site web</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>Réessayer </translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Impossible de récupérer les informations des fichiers favoris&lt;br/&gt;Veuillez %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Vous n&apos;avez pas de fichiers favoris pour l&apos;instant.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Fichier d&apos;erreurs de synchronisation</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>Aucune erreur de synchronisation</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Double-clic pour ouvrir une bibliothèque</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Bibliothèque</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Chemin</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Erreur</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Temps</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation>Entrer le jeton d&apos;authentification double facteur</translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation>Authentification double facteur</translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation>Veuillez entrer le jeton d&apos;authentification double facteur</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Fenêtre de dialogue</translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mText</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>Se souvenir de cet appareil</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Désinstallation de %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Voulez vous supprimer les informations du compte %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Suppression des informations du compte...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>Texte</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Oui</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Non</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_he_IL.ts b/i18n/seafile_he_IL.ts
new file mode 100644 (file)
index 0000000..ebf29b3
--- /dev/null
@@ -0,0 +1,3287 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="he_IL" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>נכשל בפתיחת מסד הנתונים של חשבונות</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>משימות להורדה</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>להסיר את כל המשימות המוצלחות</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>אין משימות להורדה עכשיו.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>דיאלוג</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>לפנות</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>לסגור</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>ספרייה</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>נתיב</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>בטל משימה זו</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>בטל משימה זו</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>הסר משימה זו</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>נכשל ניסיון ביטול משימה זו:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>נכשל ניסיון להסיר משימה זו:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>לצמצם</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>סגור</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>קצב הורדה הנוכחי</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>קצב העלאה הנוכחי</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>אנא בחר תיקייה לסנכרן</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>שום שרת מחובר</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>כל השרתים מחוברים</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>חלק מהשרתים אינם מחוברים</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>טופס</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>לוגו</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>לצמצם</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>סגור</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>בחר</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>או שחרר תיקייה כדי לסנכרן</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>קצב הורדה</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>חץ למטה</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>קצב העלאה</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>חץ למעלה</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>שגיאה בעת יצירת תצורת ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>נכשל בקריאה 1%</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>ליצור ספרייה</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>אנא בחר ספרייה</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>יוצר...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>נא לבחור את הספרייה כדי לסנכרן</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>התיקייה %1 אינה קיימת</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>אנא הכנס את השם</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>אנא הכנס את הסיסמה</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>סיסמאות אינן תואמות</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>שגיאה לא ידועה</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>נכשל ניסיון להוסיף משימה להורדה:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>דיאלוג</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>נתיב:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>בחר</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>שם:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>מוצפן</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>סיסמא:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>סיסמא שוב:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation> תיאור מצב</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>ביטול</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>אנא הכנס את הסיסמה</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>סנכרון ספריית &quot;1%&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>נכשל ניסיון להוסיף משימה להורדה:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>הורד ספרייה</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>בחר...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>סיסמא לספרייה זו:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>ביטול</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>אתחול %1</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>אנא בחר ספרייה</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>אתחול לא הושלם. לפרוש בכל מקרה?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>התיקייה %1 אינה קיימת</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>דיאלוג</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>לוגו</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>בחר...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>הבא</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>ביטול</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>בדיקת ספריית ברירת המחדל שלך...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>יצירת ספריית ברירת מחדל...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>נכשל ביצירת ספריית ברירת מחדל:
+
+גרסת השרת חייבת להיות 2.1 או גבוה כדי לתמוך בזה.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>מוריד ספריית ברירת מחדל...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>ספריית ברירת המחדל הורד.
+אתה יכול ללחוץ על הכפתור &quot;פתח&quot; כדי לצפות בו.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>שגיאה בעת הורדת ספריית ברירת המחדל: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>נכשל בניסיון להוריד ספריית ברירת מחדל:
+ %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>דיאלוג</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>דלג</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>הפעל ברקע</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>פתח</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>סיים</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>הורד את ספריית ברירת המחדל</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>כן</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>לוגו</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>הוסף חשבון</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>התחברות</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>שגיאת רשת:
+ %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;אזהרה:&lt;/ b&gt; תעודת SSL של שרת זה אינה מהימנה, להמשיך בכל זאת?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>אנא הכנס את כתובת השרת</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 אינו כתובת שרת חוקית</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>אנא הכנס את שם המשתמש</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>נכשל בשמירת החשבון הנוכחי</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>אנא הכנס את הסיסמה</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>דוא&quot;ל או סיסמא שגוי</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>שגיאה פנימית בשרת</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>נכשל בהתחברות: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>נכשל בהתחברות</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>דיאלוג</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>לוגו</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>סיסמא:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation> תיאור מצב</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>התחבר</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>ביטול</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>רענן</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>מסונכרן</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>יצירת אינדקס של הקבצים</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>אתחול הסינכרון</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>הורדה</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>מעלאה</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>מיזוג סנכרון</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>מחכה לסנכרון</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>שרת אינו מחובר</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>מאמת שרת</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>סינכרון אוטומטי כבוי</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>לא ידועה</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>שרת הוסר</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>אתה לא התחברת לשרת</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>אין לך הרשאה לגשת לספרייה זו</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>שטח האחסון של בעל הספרייה כבר התמלא</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>שירות מרחוק אינו זמין</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>הספרייה נמחקה בשרת</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>אתחול...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>מתחבר השרת...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>יצירת אינדקס של הקבצים</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>יצירת תיקייה...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>למזג את השינויים בקובץ...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>נשלם</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>מבטל</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>בוטל</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>ספרייה &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>ספרייה זו עדיין לא הורדה</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>שגיאה:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>דיאלוג</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>סמל מאגר</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>שם מאגר</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>תוויתטקסט</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>בעל:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>שונה לאחרונה:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>גודל:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>נתיב מקומי:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>מצב:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation> מצב המאגר</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>שם:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>לסגור</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>ספרייה זו לא בוצעה הורדה</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>עודכן לאחרונה</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>הספריות שלי</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>תת ספריות</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>להשבית סנכרון אוטומטי</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>אפשר סנכרון האוטומטי</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>לסנכרן את הספרייה זו באופן מיידי</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>ביטול הורדה</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>ביטול הורדה של ספרייה זו</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;פתח את תיקייה</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>לפתוח את התיקייה מקומית</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>ביטול &amp;סינכרון</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>נתק מסינכרן ספרייה זו</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;הצג בא ענן</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>להציג ספרייה זו ב-seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>נתק מסינכרן ספרייה זו</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>נכשל ניסיון ביטול משימה זו:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>ההורדה בוטלה</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>שגיאה לא ידועה</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>להשבית סנכרון אוטומטי</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>אפשר סנכרון האוטומטי</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>צא</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>הצג חלון ראשי</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>הגדרות</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;אודות</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>הצג תיבת אודות של היישום</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>עזרה &amp;באינטרנט</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>סנכרון אוטומטי הינו מושבת</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>חלק מהשרתים אינם מחוברים</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>מצב חיבור שרתים</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>מחובר</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>מנותק</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>דיאלוג</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>לסגור</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>הגדרות</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>דיאלוג</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>הסתר חלון ראשי בתחילה</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>הצג הודעה כאשר ספריות מסונכרנות</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>מגבלת מהירות ההורדה (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>מגבלת מהירות ההעלאה (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>0</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>ביטול</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>הסרת התקנה של 1%</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>האם אתה רוצה להסיר את פרטי חשבון של 1%?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>הסרת פרטי חשבון...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>דיאלוג</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>טקסט</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>כן</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>לא</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_hu_HU.ts b/i18n/seafile_hu_HU.ts
new file mode 100644 (file)
index 0000000..fa8f928
--- /dev/null
@@ -0,0 +1,3297 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="hu_HU" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>Információk a %1-ról</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 Kliens %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; REV %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>&amp;Névjegy</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Frissítések keresése</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>A felhasználói adatbázis megnyitása nem sikerült</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Az autentikáció lejárt, jelentkezzen be újra</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Fiókbeállítások</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Kérem, adja meg a szerver címét</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>Érvénytelen kiszolgálócím: %1</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>A fiókinformációk mentése sikertelen</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>A módosítások mentése nem sikerült: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>A fiókbeállítások frissítése sikerült</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Szerver címe</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>E-mail</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Mégsem</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>Biztos, hogy törli a fiókot: %1? &lt;br&gt;&lt;br&gt;A fiók helyileg törlésre került. Minden szinkronizációs beállítás szintén törlésre kerül. A szerveren lévő fiók nem érintett a változásban.</translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>A kötetek szinkronizálásának megszüntetése nem sikerült: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>Kattintson a weboldal megnyitásához</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>pro verzió</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Nincs felhasználói fiók beállítva</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Válasszon</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Fiókbeállítások</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Bejelentkezés</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Töröl</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Fiók hozzáadása</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Kijelentkezés</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>nincs bejelentkezve</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Űrlap</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Fiók</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>E-mail</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>Szerver</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>A fájltevékenységek funkció csak %1 Server Professional Edition-ben érhető el.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>Újra</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Nem sikerült lekérdezni a fájl tevékenységeket. Kérem, %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>A feltöltés sikeres</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Fájl &quot;%1&quot;
+feltöltése sikeres.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Fájl &quot;%1&quot;
+feltöltése nem sikerült.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Az &quot;avatars&quot; könyvtárat nem sikerült létrehozni</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Jogosultságok ellenőrzése</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Mégse</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Letöltési feladatok</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>Végrehajtott feladatok eltávolítása</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Jelenleg nincsenek letöltési feladatok.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Törlés</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Bezárás</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Kötet</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Útvonal</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Feladat megszakítása</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>Feladat megszakítása</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Feladat eltávolítása</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>A feladat megszakítása nem sikerült:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>A feladat eltávolítása nem sikerült:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Kis méret</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Bezárás</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Kötetek</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Kedvencek</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Tevékenységek</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Keres</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>Aktuális letöltési sebesség</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>Aktuális feltöltési sebesség</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Kérem, jelölje ki a szinkronizálandó mappát</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>Nincs kapcsolat a szerverrel</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>Minden kapcsolat aktív</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>Néhány szerver nem elérhető</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Űrlap</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>Embléma</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>Kis méret</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>Bezárás</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Válasszon ki</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>brand</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>vagy húzzon ide egy könyvtárat a szinkronizáláshoz</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>Letöltési sebesség</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>lefelé nyíl</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>Feltöltési sebesség</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>felfelé nyíl</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Hiba történt a ccnet konfigurálása közben</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Az előre beállított könyvtár &quot;%1&quot; nem hozható létre</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>%1 nem olvasható</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Kötet létrehozása</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Kérem, válasszon könyvtárat</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Létrehozás...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>A kötethez nem sikerült titkosítási kulcsot készíteni</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Kérem, válassza ki a szinkronizálandó könyvtárat</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>A könyvtár (%1) nem létezik</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Kérem, írja be a nevet</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Kérem, adja meg a jelszót</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>A jelszavak nem egyeznek</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Ismeretlen hiba</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>A letöltési feladat hozzáadása nem sikerült:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>A kötet nem hozható létre a szerveren:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Útvonal:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Válasszon</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Név:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>Titkosított</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Jelszó:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Jelszó ismételten:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>Állapot</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Rendben</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Mégsem</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>%1 kliens inicializálása sikertelen</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Kérem, adja meg a jelszót</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; kötet szinkronizálása</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; mappa szinkronizálása</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Szinkronizálás könyvtárba:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>vagy</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>szinkronizálás meglévő könyvtárral</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>új szinkronizáló könyvtár létrehozása</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Szinkronizálás ezzel a létező könyvtárral:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Könyvtár választás</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>A könyvtár nem létezik</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Válassz könyvtárat a szinkronizáláshoz.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>A szervezet megtiltotta hogy a kötetet a(z) %1 könyvtáron kívülre helyezze.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>&quot;%1&quot; fájl konfliktus miatt válassz másik könyvtárat.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>&quot;%1&quot; kötet konfliktus miatt válassz másik könyvtárat.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>&quot;%1&quot; könyvtár már létezik. Biztos, hogy ezzel szinkronizálja (a tartalmak összeadódnak)?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Kattintson a Nem-re ha inkább egy új könyvtárral szinkronizálná</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Alternatív könyvtárnév nem található</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>A letöltési feladat létrehozása sikertelen:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>A tároló letöltési információi nem elérhetőek:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Kötet letöltése</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>Tallózás...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>A kötet jelszava:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Rendben</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Mégsem</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Módosítások részletei</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Hozzáadott fájlok</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Törölt fájlok</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Megváltozott fájlok</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Hozzáadott könyvtárak</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Törölt könyvtárak</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Megnyitás</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Szülő ma&amp;ppa megnyitása</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Felhő fájlkezelő</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Vissza</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Előre</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Otthon</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Fájlok feltöltése</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Könyvtár feltöltése</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Nincs elegendő jogosultsága, hogy fájlokat töltsön fel a kötetbe</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Könyvtár létrehozása</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Frissítés</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Mappanév</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Érvénytelen könyvtárnév</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>A név &quot;%1&quot; már használatban van.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>újra</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Nem sikerült lekérdezni a fájlinformációkat.&lt;br/&gt;Kérem, %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>Ez a könyvtár üres.</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>A menteni kívánt fájl neve...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>A &quot;%1&quot; fájl mozgatása sikertelen</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Adja meg az elérési utat ahhoz a könyvtárhoz amibe menteni szeretne...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Felülírja a fájlt: &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>&quot;%1&quot; fájl nincs szinkronizálva</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>%1 fájl már létezik.&lt;br/&gt;Felülírja?&lt;br/&gt;&lt;small&gt;(Válassza a Nem-et alternatív néven való feltöltéshez).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>%1 fájl letöltése sikertelen</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Fájl kiválasztása feltöltéshez</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Feltöltendő könyvtár kiválasztása</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Átnevezés</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Biztosan törli a kiválasztott elemeket?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>A könyvtár létrehozása nem sikerült</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>A fájl zárolása nem sikerült</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Fájl kiválasztása feltöltéshez: %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Az átnevezés nem sikerült.</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>A törlés nem sikerült.</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>A megosztás nem sikerült.</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>A beillesztési művelet forrása és célja nem lehet azonos</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>A könyvtárat nem lehet beilleszteni a saját alkönyvtárába</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Sikertelen másolás</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Sikertelen áthelyezés</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>A könyvtár létrehozása nem sikerült.</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>Függőben</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Mégsem</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Feltölt</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Feltöltés %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Letölt</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Letöltés %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 / %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Művelet megszakítva</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>függőben</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Belső szerverhiba</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>A tárhely megtelt</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>zárolva ennél: %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Név</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Méret</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Utoljára módosítva</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Mentés mint...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>Záro&amp;l</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>Á&amp;tnevezés</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Töröl</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Megosztás csoportnak</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Frissít</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Másolás</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>&amp;Kivágás</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Beillesztés</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>L&amp;etöltés megszakítása</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Szinkronizálja ezt a könyvtárat</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Ez a funkció csak a pro verzióban érhető el.
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>%1 &amp;letöltési hivatkozás készítése</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Megosztás felhasználónak</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>%1 belső hivatkozás k&amp;észítése</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>Menté&amp;s ide mint...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Fe&amp;lold</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Írásvédett fájl törlése sikertelen</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Írásvédett fájl csonkolása sikertelen</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Könyvtárak létrehozása sikertelen</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Átmeneti állományok létrehozása sikertelen</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Fájl diszkre írása sikertelen</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Nem sikerült letörölni a letöltött fájl régi verzióját</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Sikertelen a fájl mozgatása</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 inicializálása</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>%1 könyvtár választása</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Kérem, válasszon egy könyvtárat</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Az inicializálás még nem fejeződött be. Biztosan kilép?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>A mappa (%1) nem létezik</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>Embléma</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Könyvtár választása</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Válasszon könyvtárat. A könyvtárban egy %1 alkönyvtárat hozunk létre. Ha egy kötetet letölt alapértelmezetten abba lesz lementve.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Tallózás...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Következő</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Mégsem</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1 kötetekbe szervezi a fájlokat.
+Letölti az alapértelmezett kötetet?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Alapértelmezett kötet ellenőrzése...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Alapértelmezett kötet létrehozása...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Az alapértelmezett kötet létrehozása nem sikerült:
+
+A funkció használatához a szoftver 2.1-es vagy újabb verzióját kell futtatni a szerveren.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Az alapértelmezett kötet lekérdezése nem sikerült:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Az alapértelmezett kötet létrehozása nem sikerült:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Alapértelmezett kötet letöltése...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Az alapértelmezett kötet letöltése nem sikerült:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Az alapértelmezett kötet letöltése befejeződött.
+A kötet böngészéséhez kattintson a &quot;Megnyitás&quot; gombra.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Hiba történt az alapértelmezett kötet letöltése során: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Az alapértelmezett kötet letöltése nem sikerült:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1 kötetekbe szervezi a fájlokat.
+Letölti az alapértelmezett kötetet?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Kihagyás</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Futtatás a háttérben</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Megnyitás</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Befejezés</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Alapértelmezett kötet letöltése</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Igen</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>Embléma</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>további betöltése</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Fiók hozzáadása</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Ismételt bejelentkezés</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Bejelentkezés...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Hálózati hiba:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Figyelem:&lt;/b&gt; A szerver SSL tanúsítványa nem megbízható. Elfogadja a tanúsítványt?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Kérem, adja meg a szerver címét</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>Érvénytelen elérés: %1</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Kérem, adja meg a felhasználónevet</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Kérem adja meg a számítógép nevét</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>A fiók mentése nem sikerült.</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1 szerver cím</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>A szerver címét ki kell tölteni</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1 nem egy valós szerver cím. A címnek &apos;https://&apos;-sel kell kezdődnie</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Kérem, adja meg a jelszavát</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Érvénytelen e-mail cím vagy jelszó</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Túl sok bejelentkezési kísérlet. Kérem, próbálja meg később.</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Belső szerverhiba</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Sikertelen bejelentkezés: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Sikertelen bejelentkezés</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>Embléma</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Szerver:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Példa: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>vagy: http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Jelszó:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>Állapot</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Számítógép neve:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Email / felhasználónév:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>pl. Gábor laptopja</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Bejelentkezés</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Mégsem</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Kijelentkezett. Kérem</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>jelentkezzen be</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Fiók hozzáadása</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Frissítés</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Megosztás %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Kérem írja be a csoport nevét</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Kérem adja meg a felhasználói nevet vagy e-mail címet</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>A feltöltés sikeres</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>A megosztás meghiúsult: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>A törlés sikeres</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Nem sikerült lekérdezni a könyvtár megosztási információit</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Nem sikerült lekérdezni a csoport és kapcsolat információkat</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Kérem, adja meg a felhasználónevet</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Kérem írja be a csoport nevét</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; csoport nem létezik</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Már létezik %1 csoporthoz megosztás</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Már létezik %1 felhasználóhoz megosztás</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Az előző folyamat még nem fejeződött be</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Megosztás ide:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Megosztás</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Jogosultság:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Írható-olvasható</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Csak olvasható</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Bezárás</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>Szinkronizálva</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>Fájlok indexelése</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>Szinkronizálás inicializálása</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>Letöltés</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>Feltöltés</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>Egyesítés</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>Várakozás a szinkronizálásra</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>Nincs kapcsolat a szerverrel</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>Azonosítás</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>Automatikus szinkronizálás kikapcsolva</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>Ismeretlen</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>A szerver eltávolításra került</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Nem jelentkezett be a szerverre</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Nincs jogosultsága a kötet eléréséhez</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>A kötet tulajdonosának kiosztott tárhely megtelt</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>A távoli szolgáltatás nem érhető el</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Nincs hozzáférése a szolgáltatáshoz.</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Sérült adat</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>A feltöltés elindítása sikertelen</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Nem sikerült elindítani a letöltést</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>A kötet szerveren tárolt másolata sérült</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Ütközés történt az összefésülés során</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>A szerveren futó szoftver verziója túl régi</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Ismeretlen hiba</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Hálózati hiba</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>A proxy nem található</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>A szerver nem található</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>A szerverhez nem lehet kapcsolódni</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>Nem létesíthető biztonságos kapcsolat. Ellenőrizze a szerver  SSL tanúsítványát</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation>Az adatátvitel megszakadt. Ellenőrizze a hálózatot vagy tűzfalat</translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation>Adatátviteli időtúllépés. Ellenőrizze a hálózatot vagy tűzfalat</translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation>Nem kezelt http átirányítás a szervertől. Ellenőrizze a szerver beállítását</translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Szerverhiba</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Hibás kérés</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>Nincs elég memória</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation>A kliensre nem lehet adatot írni. Ellenőrizze a tárhelyet vagy a könyvtár jogokat</translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>A tárhely kvóta megtelt</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>A kötet törölve a szerveren</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>A kötet megsérült a szerveren</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>A tárhely megtelt</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Belső szerverhiba</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Az Ön által használt %1 kliens túl régi verziójú</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>A kötet szinkronizálása nem sikerült</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>A fájlok használatban vannak egy másik folyamat által</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>A kötet törölve lett a szerverről</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Hiba történt a helyi mappa elérésekor</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>Inicializálás...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>A helyi fájlok indexelése nem sikerült</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>A szerver információk ellenőrzése sikertelen</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>A helyi fájlok létrehozása nem sikerült</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>A változások egyesítése nem sikerült</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Érvénytelen jelszó. Kérem, ismételje meg a letöltést</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Belső hiba</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>Kapcsolódás a szerverhez...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>Fájlok indexelése...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Letöltési fájl lista...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Fájlok letöltés alatt...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Könyvtár létrehozása...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Változások egyesítése...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Kész</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>szerver információ ellenőrzése...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Megszakítás</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Megszakítva</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL hiba</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Hálózati hiba: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Szerverhiba</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>A tanúsítvány-adatbázis nem nyitható meg</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>&quot;%1&quot; fájl nem létezik itt: &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 nem található olyan alkalmazás amivel a(z) %2 fájl megnyitható</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Elkészített kötet &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Törölt kötet &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>%1 átnevezése</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Nem lehet letölteni: &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>Sikertelen másolás</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Hozzáadva</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Törölve</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Törölve</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Módosítva</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Átnevezve</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Új vagy módosított</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Átmozgatva</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Könyvtár hozzáadva</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Könyvtár törölve</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Könyvtár átnevezve</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Könyvtár átmozgatva</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>fájlok</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>könyvtárak</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>és további %1 </translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>A könyvtár visszaállítva erre a státuszra:</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>&quot;%1&quot; fájl visszaállítva erre a státuszra: %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Törölt könyvtár visszaállítva</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Könyvtár neve vagy leírása változott</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>%1 rendszer automatikusan összefűzte</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Épp az imént</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>tegnap</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 napja</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1 órája</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 órája</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1 perce</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 perce</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Nem része a tanúsítványnak&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Szinkronizálja ezt a kötetet ide:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Szinkronizálja ezt a könyvtárat ide:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Mappa</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Írásvédett mappa</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Dokumentum</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF dokumentum</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Kép fájl</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Szöveges dokumentum</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Hang fájl</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Videó fájl</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Word dokumentum</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>PowerPoint dokumentum</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Excel dokumentum</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>Az útvonal (&quot;%1&quot;) ütközik a rendszer elérési útvonalával</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>Az útvonal (&quot;%1&quot;) ütközik egy meglévő kötet elérési útvonalával</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>fájl lista feltöltése</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>A fájlt más alkalmazás fogja</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>A könyvtárat más alkalmazás fogja</translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>A fájlt más felhasználó használja</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>Érvénytelen útvonal</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Hiba az indexeléskor</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>Az útvonal szóközzel vagy ponttal végződik</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>Az útvonal érvénytelen karaktert tartalmaz mint &apos;|&apos; vagy &apos;:&apos;</translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; kötet</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Ez a kötet még nincs letöltve</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Hiba:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>%1 másodpercenként</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Tároló ikonja</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>Tároló neve</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Szövegcímke</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Tulajdonos:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Utoljára módosítva:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Méret:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Helyi elérési útvonal:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Állapot:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Tároló állapota</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Név:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Szinkronizálási időköz:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Bezárás</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Ez a kötet nincs letöltve</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>&quot;%1&quot; fájlt nem lehet megnyitni a nemlétező kötetből: &quot;%2&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Mostanában frissült könyvtárak</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Saját kötetek</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Alkötetek</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Velem megosztva</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Mindenkivel megosztva</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Csoportokkal megosztva</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Szinkronizált könyvtárak</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>Szinkronizálás inicializálása</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Automatikus szinkronizálás kikapcsolása</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Automatikus szinkronizálás bekapcsolása</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>&amp;Tulajdonságok megjelenítése</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Kötet tulajdonságai</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Szinkronizálja ezt a kötetet</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Szinkronizálja ezt a kötetet</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Mostanában frissült könyvtárak</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Szinkronizálás &amp;most</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Kötet azonnali szinkronizálása</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Letöltés megszakítása</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>A kötet letöltésének megszakítása</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Mappa megnyitása</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>Helyi mappa megnyitása</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>&amp;Helyi mappa megnyitása</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Szinkronizálás befejezése</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>Kötet szinkronizálásának megszüntetése</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>Megnyitás a &amp;felhőben</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>Kötet böngészése a seahub-on</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Megosztás felhasználónak</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Kötet megosztása a felhasználónak</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Megosztás csoportnak</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Kötet megosztása csoporttal</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>Fe&amp;lhő fájlkezelő megnyitása</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>kötet megnyitása beágyazott fájlkezelőben</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Kötet újraszinkronizálása</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>kötet szinkronizálásának megszüntetése és újraszinkronizálása</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Sz&amp;inkronizálási időköz beállítása</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>A kötet (&quot;%1&quot;) szinkronizálását nem sikerült megszüntetni</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>A művelet megszakítása sikertelen:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Letöltés megszakítva</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Nincs joga feltölteni ebbe a könyvtárba</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>&quot;%1&quot; fájl nem írható felül saját magával</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>A &quot;%1&quot; fájl törlése nem sikerült.</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Sikertelen feltöltés: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Szinkronizálási időköz (másodpercben):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; kötet szinkronizálási időközének beállítása</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>Kötetek keresése</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>újra</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Nem sikerült lekérdezni a kötet információkat.&lt;br/&gt;Kérem, %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Figyelem:&lt;/b&gt; A szerver biztonsági tanúsítványa nem megbízható. Folytatja a kapcsolódást?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>nem sikerült hozzáadni az alapértelmezett fiókot </translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>A naplózás elindítása nem sikerült: %S</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Rendben</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Igen</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nem</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Mégsem</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>%1 belső link</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Vágólapra másol</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Rendben</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Ismeretlen hiba</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Automatikus szinkronizálás kikapcsolása</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Automatikus szinkronizálás bekapcsolása</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Kilépés</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Főablak megnyitása</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Beállítások</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>%1 könyvtár &amp;megnyitása</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>%1 mappa megnyitása</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Nap&amp;lózási mappa megnyitása</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>Fájl szinkronizációs hibák megmutatása</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Névjegy</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Megjeleníti az alkalmazás névjegyét</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Online segítség</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Fájl</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>Automatikus szinkronizálás kikapcsolva</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Feltöltés</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Letöltés</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>%1 naplóállományok könyvtárának megnyitása</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>%1 online súgó megnyitása</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>Néhány szerver nem elérhető</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Könyvtárban mutat</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Könyvtárban mutat</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>Fájlok keresése</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>újra</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Keresés sikertelen&lt;br/&gt;Kérem, %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Kapcsolódás állapota</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>Kapcsolódva</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>Nincs kapcsolat</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Bezárás</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Kérem adja meg a kötet jelszavát</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Jelszó megadása ehhez a kötethez: %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Adja meg a jelszót</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Érvénytelen jelszó</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Ismeretlen hiba</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Rendben</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Mégsem</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Beállítások</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>%1 automatikus elindítása bejelentkezéskor</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>Ne jelenjen meg %1 ikonja a tálcán</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Nincs</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP proxy</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5 proxy</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Rendszer Proxy</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Megváltoztatta a felület nyelvét. Újraindítja az alkalmazást a beállítás érvényesítéséhez?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>A proxy kiszolgáló címe nem lehet üres</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>Helytelen Proxy portszám</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>A proxy felhasználói név nem lehet üres</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>A proxy jelszó nem lehet üres</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Főablak elrejtése indításkor</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Értesítést kérek, ha a kötetek szinkronizálva vannak</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>MS Office/Libreoffice ideiglenes fájlok szinkronizálása</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Letöltési sebesség korlátozása (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Feltöltési sebesség korlátozása (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Alap</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>A szinkronizálás maradjon bekapcsolva</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>A szinkronizálás maradjon bekapcsolva a helyi mappa törlése vagy elérhetetlensége esetén</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Ne legyen megszüntetve a szinkronizálás, ha a kötet nem létezik a szerveren</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Ne legyen automatikusan megszüntetve a szinkronizálás, ha a kötet nem létezik a szerveren</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>„FinderSync” kiterjesztés engedélyezése</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>„Explorer” kiterjesztés engedélyezése</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>Frissítések automatikus keresése</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Tanúsítványellenőrzés kikapcsolása HTTPS-alapú szinkronizálásnál</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Szinkronizálás engedélyezése létező könyvtárral más névvel</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Haladó</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Nyelv (újraindítást igényel)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Nyelv</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Proxy típusa:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Szerver:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Port:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Felhasználónév:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Jelszó:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>A proxy szerver jelszót igényel</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Hálózat</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Rendben</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Mégsem</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Írható olvasható</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Csak olvasható</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Megosztás megszüntetése</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>Kattintson a szerkesztéshez</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>%1 készítette</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Írható olvasható</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Csak olvasható</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Csoport</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Felhasználó</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Jogosultság</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Az előző folyamat még nem fejeződött be</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Megosztás link</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Megosztása link:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Közvetlen letöltés</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Vágólapra másol</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Rendben</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Nem megbízható kapcsolat</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>A szerver (%1) érvénytelen biztonsági tanúsítványt használ, ezért a kapcsolat nem megbízható. Folytatja a kapcsolódást?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Jelenlegi RSA-kulcs ujjlenyomata: %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Előző RSA-kulcs ujjlenyomata: %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Választás megjegyzése</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Igen</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nem</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Megnyitás</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Fájl megnyitása</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>megtekintés &amp;Weben</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>fájl megtekintése a weboldalon</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>újra</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Nem sikerült lekérdezni a kedvenc fájlok információit&lt;br/&gt;Kérem, %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Nincsenek kedvenc fájljai.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Fájl szinkron hibák</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>Nincsenek szinkronizációs hibák. </translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Kötet megnyitása dupla kattintással</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Kötet</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Útvonal</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Hiba</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Idő</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>%1 eltávolítása</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Biztosan eltávolítja a következő fiók beállításait: %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Fiókinformációk eltávolítása...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Párbeszédablak</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>szöveg</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Igen</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nem</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_is.ts b/i18n/seafile_is.ts
new file mode 100644 (file)
index 0000000..cfa5949
--- /dev/null
@@ -0,0 +1,3295 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="is" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>mistókst að opna gagnagrunn reiknings</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Aðgangur útrunninn, vinsamlegast skráðu þig inn aftur</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Persónulegar stillingar</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Vinsamlegast setjið inn veffang þjóns</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 er ekki rétt veffang þjóns</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Mistókst að vista reikningsupplýsingar</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Mistókst að vista breytingarnar: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Tókst með ágætum að uppfæra reikningsupplýsingar</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Svargluggi</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Veffang Þjóns</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Netfang</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Í lagi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Hætta við</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Mistókst að taka samstilla af fyrir þennan reikning: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>smelltu til að opna vefsíðuna</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>Sér útgáfa</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Enginn reikningur</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Veldu</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Stillingar reiknings</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Innskrá</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Eyða</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Bæta við reikningi</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Útskrá</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>ekki skráður inn</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Form</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Reikningur</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>netfang</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>þjónn</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Virkni er aðeins studd í %1 Server Professional Edition.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reyna aftur</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Mistókst að sækja upplýsingar um hreyfingar. Vinsamlegast %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Upphleðsla Tókst</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Skrá &quot;%1&quot;
+hlaðið upp giftursamlega.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Skrá &quot;%1&quot;
+mistókst að hlaða upp.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Mistókst að búa til skráarsafn fyrir smámyndir</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Niðurhalsverk</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>fjarlægja öll verk sem eru kláruð</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Engin niðurhalsverk akkúrat núna.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Svargluggi</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Hreinsa</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Loka</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Safn</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Slóð</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Hætta við þetta verk</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>hætta þessu verki</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Fjarlægja þetta verk</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Mistókst að hætta við þetta verk:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Mistókst að fjarlægja þetta verk:
+
+ %1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minnka</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Loka</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Söfn</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Stjörnumerkt</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Hreyfingar</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Leita</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>núverandi niðurhalshraði</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>núverandi upphleðsluhraði</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Vinsamlegast veldu skáarsafn til að samkeyra</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>enginn þjónn tengdur</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>allir þjónar tengdir</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>sumir þjónar ekki tengdir</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Form</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minnka</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>loka</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Veldu</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>brand</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>eða Dragðu og Slepptu skráarsafni hingað</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>niðurhalshraði</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>ör niður</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>upphleðsluhraði</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>ör upp</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Villa þegar verið var að búa til styllingar fyrir ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Get ekki búið til frumstillt möppu &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>tókst ekki að lesa %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Búa til safn</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Vinsamlegast veldu skráarsafn</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Er að búa til...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Mistókst að útbúa dulkóðunarlykil fyrir þetta safn</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Vinsamlegast veldu skráarsafn til að samstilla</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Skráarsafnið %1 er ekki til</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Vinsamlegast sláðu inn nafn</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Vinsamlegast sláðu inn lykilorðið</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Lykilorðin stemma ekki</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Óþekkt villa</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Tókst ekki að bæta við niðurhalsverki:
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Mistókst að búa til safn á þjóni:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Svargluggi</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Slóð:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Veldu</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nafn:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>dulkóðað</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Lykilorð:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Endurtaktu Lykilorðið:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>stöðutexti</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Í lagi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Hætta við</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>%1 biðlara mistókst að frumstilla</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Vinsamlegast sláðu inn lykilorðið</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Samstilla safn &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Samstilla möppu &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Samkeyra við möppu:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>eða</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>samkeira með möppu ser er nú þegar til</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>búa til nýja samkeyrslumöppu</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Samkeyra með þessari möppu:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Vinsamlegast veldu möppu</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>Þessi mappa er ekki til</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Vinsamlegast veldu möppu til að samkeyra</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Samfélagið sem þú tilheyrir hefur afvirkjað möguleikann að setja safn útfyrir %1 möppuna.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Rekst á við skránna &quot;%1&quot; sem er nú þegar til, vinsamlegast veldu aðra möppu.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Rekst á við möppuna &quot;%1&quot; sem er nú þegar til, vinsamlegast veldu aðra</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>Mappan &quot;%1&quot; er þegar til. Ertu viss um að þú viljir samkeyra við hana (efni hennar verður skeytt inn)?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Veldu Nei til að samkeyra frekar við nýja möppu</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Get ekki fundið annað möppunafn</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Mistókst að bæta við niðurhalsverki:
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Mistókst að sækja niðurhalsgeymsluupplýsingar :
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Hala niður safni</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>veldu...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Lykilorð fyrir þetta safn:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Í lagi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Hætta við</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Breytingar í smáatriðum</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Bætti við skrám</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Eyddar skrár</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Breyttar skrár</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Nýjar möppur</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Eyddar möppur</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Opna</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Opna &amp;yfir skáasafn</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Skýjavafri</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Til baka</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Áfram</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Heim</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Hlaða upp skrám</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Hlaða upp möppu</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Þú hefur ekki réttindi til að upphlaða skrám í þetta safn</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Búa til möppu</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Endurglæða</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Möppunafn</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Óleyfilegt möppunafn!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>Þetta nafn &quot;%1&quot; er þegar í notkun.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reyna aftur</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Mistókst að sækja upplýsingar skáa&lt;br/&gt;Vinsamlegast %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Sláðu inn nafn á skrá til að vista í...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Gat ekki fjarlægt skránna &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Sláðu inn slóð möppunnar sem þú vilt vista í...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Vilti örugglega yfirskrifa núverandi skrá &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>Skrá &quot;%1&quot; hefur ekki verið samstillt</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Skrá %1 er þegar til.&lt;br/&gt;Viltu yfirskrifa hana?&lt;/br/&gt;&lt;/small&gt;(Veldu Nei til að hlaða upp með öðru nafni).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Mistókst að niðurhala skrá: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Veldu skrá til að hlaða upp</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Veldu möppu til að hlaða upp</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Endurnefna</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Viltu virkilega eyða þessum atriðum</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Mistókst að búa til möppu</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Læsing skráar mistókst</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Veldu skrá til að uppfæra %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Endurnefning mistókst</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Eyðing mistókst</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Deiling mistókst</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Get ekki sleppt skránum í sama skráasafn</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Afritun mistókst</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Færsla mistókst</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Mistókst að búa til safn!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Hætta við</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Upphlaða</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Hleð upp %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Niðurhala</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Hala niður %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 af %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Hætt við aðgerð</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>yfirstandandi</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Innri Kerfisvilla</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>læst af %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Nafn</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Stærð</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Síðast Breytt</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Vista sem...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Læsa</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Endurnefna</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Eyða</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Deila með Hópi</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Uppfæra</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Copy</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Cu&amp;t</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Paste</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Hætt&amp;a við niðurhal</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Samkeyra þessu skráasafni</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Þessi virkni er aðeins aðgengileg í &quot;pro&quot; útgáfunni
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>&amp;Gera %1 Niðurhalshlekk</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Deila með Notanda</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>G&amp;era %1 Innri Hlekk</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Vista sem í...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Af&amp;læsa</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Get ekki fjarlægt skrifvarnar skrár</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Get ekki klippt skrifvarðar skrár</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Mistókst að búa til skráarsöfn</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Mistókst að búa til tímabundna skrá</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Mistókst að skrifa skrá á disk</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Mistókst að eyða eldri útgáfu af niðurhöluðu skránni</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Mistókst að færa skrá</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 Frumstillt</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Veldu %1 möppu</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Vinsamlegast veldu skráarsafn</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Frumstillingu er ekki lokið. Virkilega hætta núna?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Skráarsafnið %1 er ekki til</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Svargluggi</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Veldu möppu</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Vinsamlegast veldu möppu. Við munum búa til %1 undirmöppu í henni. Þegar þú halar niður safni, þá er það sjálfgefið að vista þar.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Veldu...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Næsta</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Hætta við</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Athuga sjálfgefna skráarsafnið þitt...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Bý til sjálfgefna safnið...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Mistókst að eyða sjálfgefnu safni:
+
+Þjónsútgáfan verður að vera 2.1 eða hærri til að styðja þetta</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Mistókst að sækja sjálfgefið safn:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Mistókst að búa til sjálfgefið safn:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Hala niður sjálfgefna safninu...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Mistókst að hala niður sjálfgefnu safni:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Sjálfgefna safninu hefur verið halað niður.
+Þú getur smellt á &quot;Opna&quot; takkann til að skoða það.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Villa þegar verið var að hala niður sjálfgefna safninu: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Mistókst að hala niður sjálfgefnu safni:
+ %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Samræður</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Sleppa</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Keyra í Bakgrunni</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Opna</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Enda</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Hala niður Sjálfgefnu Safni</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Já</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Bæta við reikningi</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Endur-innskráning</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Er að innskrá...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Netvilla:
+ %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Viðvörun:&lt;/b&gt; ssl skilríkið fyrir þennan þjón er ótreyst, halda samt áfram?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Vinsamlegst sláðu inn veffang þjóns</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 er ekki gilt vefang þjóns</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Vinsamlegst sláðu inn notendanafn</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Vinsamlegast skráðu heiti tölvunnar</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Mistókst að vista reikninginn</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1 Veffang Þjóns</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Vinsamlegast sláðu inn lykilorð</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Ekki rétt netfang eða lykilorð</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Ert að skrá þig inn of ört, vinsamlegast bíddu aðeins</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Innri Kerfisvilla</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Innskráning mistókst: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Innskráning mistókst</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Svargluggi</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Þjónn:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Til dæmis: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>eða http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Lykilorð:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>stöðutexti</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Tölvunafn:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Netfang / Notendanafn:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>t.d Siggu tölva</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Innskrá</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Hætta við</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Þú er útskráð(ur). Vinsamlegast</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>innskrá</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Bæta við reikningi</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Endurglæða</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Deila %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Sláðu inn nafn hópsins</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Tókst að hlaða upp</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>Deiliaðgerð mistókst: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Tókst að fjarlægja</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Mistókst að sækja upplýsingar um möppuna</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Mistókst að sækja hópa og tengiliðstupplýsingarnar þínar</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Vinsamlegast sláðu inn notendanafnið</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Vinsamlegast sláðu inn hópanafnið</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>Enginn slíkur hópur &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Þegar deilt með hópi %1</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Þegar deilt með notanda %1</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Síðasta aðgerð er enn í vinnslu</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Samræður</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Deila Með:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Deila</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Réttindi:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Lesa-Skrifa</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Aðeins-Lesa</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Loka</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>samstillt</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>Bý til yfirlit yfir skrár</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>frumstilli samstillingu</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>hala niður</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>hleð upp</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>sameina samstillingar</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>bíð eftir samstilingu</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>þjónn ekki tengdur</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>auðkenning þjóns</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>slökkt er á sjálfvirkri samstillingu</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>óþekkt</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Þjónninn hefur verið fjarlægður</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Þú hefur ekki skráð þig inn</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Þú hefur ekki aðgangsleyfi að þessu safni</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Geymslupláss eiganda þessa safns er fullt</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Fjarþjónusta er ekki í boði</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Aðgangur að þjónustu óheimil</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Sködduð innri gögn</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Upphleðsla mistókst</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Mistókst að niðurhala</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Safn er skaddað á þjóni</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Misræmi í sameiningu</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Útgáfa á þjóni er of gömul</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Óþekkt villa</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Geymslukvóti hefur verið fullnýttur</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Innri kerfisvilla</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>%1 biðlarinn þinn er of gamall</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Mistókst að samstilla þetta safn</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Skrár eru læstar af öðru forriti</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Safni er eytt á þjóni</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Það kom upp villa þegar reynt var að tengjast skráarsafni á tölvunni þinni</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>Frumstilli...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>tengist þjóni...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>Bý til yfirlit yfir skár...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Hala niður skráalista...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Hala niður skrám...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Bý til skráarsafn...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Sameina skráarbreytingar...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Búin</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Hætta við</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Hætt við</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL Villa</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Netvilla: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Kerfisvilla</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>mistókst að opna vottorðagagnagrunn</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>Skrá &quot;%1&quot; er ekki til í &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 gat ekki fundið forrit til að opna skránna %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Bjó til safnið &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Eyddi safninu &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Endurnefna %1 sem</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Gat ekki niðurhalað atriði &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>afritun mistókst</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Bætt við</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Eytt</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Fjarlægt</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Breytt</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Endurnefnt</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Bætt við eða breytt</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Fært</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Bætti við skráarsafni</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Fjarlægði skráarsafn</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Endurnefndi skráarsafn</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Færði skráarsafn</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>skrár</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>skráarsöfn</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>og %1 fleiri</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Setti stöðu safns á</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Snéri skrá &quot;%1&quot; aftur í stöðu &quot;%2&quot; </translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Endurheimti eyddu skráarsafni</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Breytti nafni eða lýsingu skráarsafns</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>Sameinað sjálfvirkt af %1 kerfi</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Rétt í þessu</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>Fyrir einum degi síðan</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>Fyrir %1 dögum síðan</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>Fyrir einni klukkustund síðan</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>Fyrir %1 klukkustundum síðan</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>Fyrir einni mínútu síðan</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>Fyrir %1 mínútum síðan</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Not Part of Certificate&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Samkeyra þessu safni með:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Samkeyra þessu skráasafni með:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Skráasafn</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Skrifvarið Skráasafn</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Skjal</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF Skjal</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Myndaskrá</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Textaskjal</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Hljóðskrá</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Vídeóskrá</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Word skjal</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>PowerPoint skjal</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Excel skjal</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>Slóðin &quot;%1&quot; rekst á við kerfisslóð</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>Slóðin &quot;%1&quot; rekst á við safn sem þegar er til</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Safn &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Ekki er enn búið að hala niður þessu safni</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Villa:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>hverjar %1 sekúndur</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Svargluggi</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>SafnaSmámynd</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>SafnaNafn</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>TextaMerki</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Eigandi:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Síðast Breytt:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Stærð:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Staðvær Slóð:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Staða:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>SafnaStaða</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nafn:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Samstillingartíðni:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Loka</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Þessu safni hefur ekki enn verið halað niður</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>Get ekki opnað skrá &quot;%1&quot; því safnið &quot;%2&quot; er ekki til</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Nýlega Uppfært</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Söfnin mín</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Undirsöfn</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Samstillt Söfn</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>frumstilli samstillingu</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Afvirkja sjálfvirka samstillingu</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Virkja sjálfvirka samstillingu</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Sýna &amp;smáatriði</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Sýna smáatriði varðandi þetta safn</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Samstilla þetta safn</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Samstilla þetta safn</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Nýlega Uppfært</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Samkeyra &amp;núna</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Samkeyra þetta safn núna</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Hætta við niðurhal</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Hætta við niðurhal á þessu safni</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Opna skráarsafn</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>opna staðvært skráarsafn</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Samstilling Af</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>aftengja þetta safn</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Skoða í skýi</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>skoða þetta safn á seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Deila með notanda</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Deila þessu safni með notanda</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Deila með hópi</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Deila þessu safni með hópi</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Opna skráavafra skýs</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>opna þetta safn í innbyggðum Skráavafra Skýs </translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Endursamstilla þetta safn</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>Taka af og setja aftur á samstillingu fyrir þetta safn</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Setja &amp;samstillingartíðni</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Mistókst að aftengja safnið &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Mistókst að hætta við þetta verk:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Hætt var við niðurhalið</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>Gat ekki yfirskrifað skrána &quot;%1&quot; með sjálfri sér</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Gat ekki eytt skránni &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Mistókst að hlaða upp skránni: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Samstillinartíðni (í sekúndum):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Setja Samstillingartíðni Fyrir Safn &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reyna aftur</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Tókst ekki að sækja upplýsingar um safn&lt;br/&gt;Vinsamlegast %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Viðvörun:&lt;/b&gt; ssl skírteinið fyrir þennan þjón er ekki traust, halda samt áfram?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>mistókst að bæta við sjálfgefnum reikningi</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Mistókst að frumstilla skrá: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Í lagi</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Já</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nei</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Hætta við</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>%1 Innri Hlekkur</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Afrita í skyndimynni</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Í Lagi</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Óþekkt villa</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Skökkva á sjálfvirkri samstillingu</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Kveikja á sjálfvirkri samstillingu</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Hætta</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Sýna aðalglugga</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Stillingar</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Opna %1 &amp;skráasafn</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>opna %1 skáasafn</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Opna skráarsafn &amp;skráninga</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Um</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Sýna upplýsingar um forritið</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Hjálp á netinu</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Skrá</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>slökkt er á sjálfvirkri samstillingu</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Hleð upp</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Hala niður</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>opna %1 sögu skráasafns</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>opna %1 hjálp á netinu</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>sumir þjónar ekki tengdir</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Sýna í skráasafni</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Sýna í skráasafni</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>reyna aftur</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Leit mistókst&lt;br/&gt;Vinsamlega %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Tengistaða þjóns</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>tengt</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>aftengt</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Samræða</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Loka</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Vinsamlegast sláðu inn lykilorð safnsins</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Sláðu inn lykilorð fyrir safnið %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Vinsamlegast sláðu inn lykilorð</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Rangt lykilorð</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Óþekkt villa</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Samræður</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Í lagi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Hætta við</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Stillingar</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>Keyra %1 upp sjálfvirkt eftir innskráningu</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>Fela %1 smámynd frá stjórnstiku</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Ekkert</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP Proxy</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5 Proxy</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Proxy Kerfi</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Þú hefur skipt um tungumál. Endurræsa til að virkja það?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>Proxy veffang má ekki vanta</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>Proxy tengið er rangt</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>Proxy notandanafn má ekki vanta</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>Proxy lykilorð má ekki vanta</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Samræður</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Fela aðalglugga í ræsingu</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Láta vita þegar söfn eru samstillt</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Virkja samstillingu tímabundinna skráa af gerð MSOffice/Libreoffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Takmörkun á hraða niðurhals (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Takmörkun á hraða uppleðslu (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Einfallt</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Ekki taka samstillingu sjálfvirkt af safni</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Ekki taka samkeyrslu af safni þegar skráarsafn á tölvu er fjarlægt eða ekki aðgengilegt af einhverjum völdum.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Ekki taka samstillingu af safni þegar það finnst ekki á þjóni</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Ekki taka samstillingu af safni sjálfvirkt þegar það finnst ekki á þjóni</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Virkja FinderSync viðbót</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Virkja Explorer viðbót</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Ekki sannvotta skírteini í HTTPS samstillingu</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Virkja samkeyrslu við skráasafn sem er nú þegar til undir öðru nafni</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Ýtarlegt</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Tungumál (þarfnast endurræsingar)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Tungumál</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Staðgengilsgerð:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Hýsill:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Tenginúmer:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Notendanafn:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Lykilorð:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Staðgengilsþjónn krefst lykilorðs</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Net</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Í lagi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Hætta við</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Lesa Skrifa</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Aðeins Lesa</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Fjarlægja Deilingu</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Búið til af %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Lesa Skrifa</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Aðeins Lesa</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Hópur</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Notandi</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Réttindi</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Síðasta aðgerð er enn í vinnslu</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Deila Hlekk</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Deila hlekk:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Beint Niðurhal</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Afrita í biðminni</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Í Lagi</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Ótraust tenging</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 notar rangt öryggisskíreini.  Tengingin er hugsanlega óörugg. Viltu halda áfram?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Núverandi RSA fingrafar er %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Fyrra RSA fingrafar var %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Samræða</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Mundu valið mitt</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Já</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nei</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>%Opna</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Opnaðu þessa skrá</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>skoða á &amp;Vef</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>skoða þessa skrá á vefsíðu</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>reyna aftur</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Mistókst að sækja upplýsingar um stjörnumerktar skrár&lt;br/&gt;Vinsamlegast %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Þá hefur ekki stjörnumerkt skrár enn</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Fjarlægja %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Viltu fjarlægja reikningsupplýsingar %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Fjarlægi reikningsupplýsingar...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Svargluggi</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>texti</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Já</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nei</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_it.ts b/i18n/seafile_it.ts
new file mode 100644 (file)
index 0000000..e8cabd1
--- /dev/null
@@ -0,0 +1,3297 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="it" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>Informazioni su %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt;REV %1&lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>Informazioni</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Controlla aggiornamenti</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>Impossibile aprire il database degli account</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Autorizzazione scaduta, per favore effettua il login</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Impostazioni account</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Inserisci l&apos;indirizzo del server</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 non è un indirizzo valido per il server</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Impossibile salvare le informazioni dell&apos;account</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Impossibile salvare i cambiamenti: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Informazioni dell&apos;attuale account correttamente aggiornate</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Indirizzo Server</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Email</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annulla</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>Sei sicuro di voler rimuovere l&apos;account %1?&lt;br&gt;&lt;br&gt;L&apos;account sarà rimosso localmente. Anche tutte le configurazioni di sincronizzazione saranno rimosse. L&apos;account sul server non sarà toccato.</translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Impossibile scollegare le librerie dell&apos;account: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>Clicca per aprire il sito web</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>Versione Pro</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Nessun account</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Scegli</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Impostazioni account</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Login</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Cancella</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Aggiungi un account</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Disconnetti</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>non autenticato</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Modulo</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Account</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>email</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>server</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Le Attività File sono supportate soltanto in %1 Server Professional Edition.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>riprova</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Impossibile ottenere informazioni sulle attività.&lt;br\&gt;Per favore %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Caricamento riuscito</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>File &quot;%1&quot;
+caricato con successo.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>File &quot;%1&quot;
+non caricato a causa di un errore.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Errore di permessi!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorizzazione scaduta</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Il file non esiste</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Errore di caricamento: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Impossibile creare cartella degli avatar</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Controllo i permessi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annulla</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Attività di scaricamento</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>rimuovi tutte le attività completate con successo</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Nessun processo di scaricamento attivo.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Svuota</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Chiudi</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Libreria</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Percorso</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Annulla questa attività</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>annulla questa attività</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Rimuovi questa attività</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Impossibile annullare questa attività:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Impossibile rimuovere questa attività:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimizza</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Chiudi</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Librerie</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Preferiti</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Attività</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Ricerca</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>velocità di scaricamento attuale</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>velocità di caricamento attuale</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Per favore Scegli una cartella da sincronizzare</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>nessun server connesso</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>tutti i server sono connessi</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>alcuni server non sono connessi</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Modulo</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimizza</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>chiudi</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Seleziona</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>marchio</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>o trascina qui la cartella per sincronizzarla</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>velocità di scaricamento</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>Freccia Giù</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>velocità di caricamento</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>Freccia Su</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Errore nel creare la configurazione ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Impossibile creare la directory di preconfigurazione &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>impossibile leggere %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Crea una libreria</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Scegli una cartella</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Creazione...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Impossibile generare la chiave di cifratura per questa libreria</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Scegli la cartella da sincronizzare</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>La cartella %1 non esiste</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Inserisci il nome</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Inserisci la password</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Le password non corrispondono</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Errore sconosciuto</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Impossibile aggiungere l&apos;attività di download
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Impossibile creare la libreria sul server:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Percorso:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Scegli</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nome:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>cifrato</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Password:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Ripeti la Password:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>testo di stato</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annulla</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>Impossibile inizializzare il client %1</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Inserire la password</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Sincronizza la libreria &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Sincronizza la cartella &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Sincronizza con la cartella:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>oppure</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>sincronizza con una cartella esistente</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>crea una nuova cartella di sincronizzazione</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Sincronizza con questa cartella esistente:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Scegli una cartella</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>La cartella non esiste</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Scegli la cartella da sincronizzare.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>La tua organizzazione vieta di collocare una libreria al di fuori della cartella %1.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>In conflitto con il file esistente &quot;%1&quot;, scegli un&apos;altra cartella.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>In conflitto con la libreria esistente &quot;%1&quot;, scegli un&apos;altra cartella.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>La cartella &quot;%1&quot; esiste già. Vuoi davvero sincronizzare con essa (i contenuti saranno riuniti)?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Seleziona No per sincronizzare invece con una nuova cartella</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Impossibile trovare un nome alternativo per la cartella</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Impossibile aggiungere l&apos;attività di scaricamento:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Impossibile ottenere informazioni sullo scaricamento della libreria:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Scarica libreria</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>scegli...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Password per questa libreria:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annulla</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Dettagli delle modifiche</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>File aggiunti</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>File cancellati</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>File modificati</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Cartelle aggiunte</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Cartelle cancellate</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Apri</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Apri directory &amp;superiore</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Visualizzatore dei file remoti</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Indietro</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Avanti</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Home</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Carica file</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Carica una cartella</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Non hai il permesso di caricare file in questa libreria</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Crea una cartella</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Aggiorna</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 oggetti</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Nome della cartella</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Nome della cartella non valido!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>Il nome &quot;%1&quot; è già in uso.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>riprova</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Impossibile caricare le informazioni sui file&lt;br/&gt;Per favore %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>Questa cartella è vuota.</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Inserisci il nome del file per il salvataggio...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Impossibile cancellare il file &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Inserisci il percorso della cartella per il salvataggio...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Vuoi sovrascrivere il file esistente &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>Il file &quot;%1&quot; non è stato sincronizzato</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Il file %1 esiste già.&lt;br/&gt;Vuoi sovrascriverlo?&lt;br/&gt;&lt;small&gt;(Scegli No per caricarlo usando un altro nome.)&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Il file non esiste</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Impossibile scaricare il file: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Scegli un file da caricare</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Scegli una cartella da caricare</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Rinomina</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Vuoi davvero cancellare questi oggetti</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Impossibile creare la cartella</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Impossibile bloccare il file</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Scegli un file da caricare %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Impossibile rinominare</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Impossibile cancellare</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Impossibile condividere</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Non puoi incollare file dalla stessa cartella</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>Non puoi incollare la cartella in una sua sottocartella</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Impossibile copiare</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Impossibile spostare</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Impossibile creare la libreria</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Non hai i permessi per caricare in questa cartella</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorizzazione scaduta</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Errore di Permessi!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Libreria/Cartella non trovata.</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation>Impossibile caricare il file %1: %2</translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation>Impossibile creare la cartella della cache</translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation>Impossibile aprire la cartella della cache</translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Cerca file</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>In corso</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annulla</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Carica</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Sto caricando %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Scarica</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Sto scaricando %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 di %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>Impossibile caricare il file: &quot;%1&quot;, vuoi riprovare?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>Riprova</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Salta</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Annulla</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>Sto salvando</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>Salvataggio del file fallito</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Nome</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Dimensione</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Ultima Modifica</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Mostra nella cartella</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Mostra nella cartella</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Operazione annullata</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>in corso</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>attività annullata</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Errore interno del server</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>La quota di spazio disponibile è stata esaurita</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>bloccato da %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Nome</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Dimensione</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Ultima modifica</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Salva con nome...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Blocca</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Rinomina</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>Ca&amp;ncella</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Condividi con il gruppo</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Aggiorna</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Copia</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>&amp;Taglia</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Incolla</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>&amp;Annulla scaricamento</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Sincronizza questa cartella</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Questa funzionalità è disponibile solo nella versione pro
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>&amp;Genera il link %1 per scaricare</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Condividi con l&apos;utente</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>G&amp;enera il link %1 interno</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Salva col nome in...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Sb&amp;locca</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Impossibile cancellare file in sola lettura</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Impossibile tagliare file in sola lettura</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>Ritenta il caricamento</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>Cancella la versione locale </translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>Salva la versione locale come...</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation>Apri la cartella locale della Cache</translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Impossibile creare le cartelle</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Impossibile creare file temporanei</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Impossibile scrivere file su disco</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Impossibile rimuovere la versione più vecchia del file scaricato</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Impossibile spostare il file</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 Inizializzazione</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Scegli la cartella %1</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Scegli una cartella</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Inizializzazione non completata. Vuoi davvero terminare?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>La cartella %1 non esiste</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Scegli una cartella</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Per favore, scegli una cartella. Al suo interno sarà creata la sottocartella %1. Quando scaricherai una libreria, sarà salvata in quella posizione per default.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Scegli...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Prossimo</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancella</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1 organizza i file in librerie.
+Vuoi scaricare la tua libreria predefinita?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Sto verificando la tua libreria predefinita...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Sto creando la libreria predefinita...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Impossibile creare la libreria predefinita:
+
+La versione del server deve essere 2.1 o più alta per supportare questa funzione.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Impossibile accedere alla libreria predefinita:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Impossibile creare la libreria predefinita:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Sto scaricando la libreria predefinita...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Impossibile scaricare la libreria predefinita:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>La libreria predefinita è stata scaricata.
+Premi il pulsante &quot;Apri&quot; per visualizzarla.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Errore durante lo scaricamento della libreria predefinita: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Impossibile scaricare la libreria predefinita:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1 organizza i file in librerie.
+Vuoi scaricare la tua libreria predefinita?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Salta</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Esegui in background</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Apri</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Finisci</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Scarica libreria predefinita</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sì</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>carica altro</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>Caricamento dei file di log falliti</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Caricamento dei file di log</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Errore di permessi!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Libreria/Cartella non trovata.</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorizzazione scaduta</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>Fallito il caricamento del file di log: %1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>Caricamento dei file di log riuscito </translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>In compressione</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annulla</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 di%2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Aggiungi un account</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>Accesso singolo</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Nuovo login</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Sto entrando...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Errore di Rete:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Attenzione:&lt;/b&gt; Il certificato ssl di questo server non è verificato, procedere comunque?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>inserisci l&apos;indirizzo del server</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 non è un nome valido per il server</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Inserisci il nome utente</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Per favore inserisci il nome del computer</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Impossibile salvare l&apos;account corrente</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1 Indirizzo del Server</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>L&apos;indirizzo del server non può essere vuoto</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1 non è un indirizzo valido. Deve iniziare con &quot;https://&quot;</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Inserisci la password</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Email o password sbagliati</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Ti stai autenticando con troppa frequenza, per favore attendi un minuto</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Errore Interno del Server</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Impossibile effettuare il login: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Accesso fallito</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Server:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Per esempio: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>o http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Password:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>stato testo</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Nome del Computer:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Email / Nome Utente:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>e.g. PC di Mario Rossi</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Accesso</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancella</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Login Automatico</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Sei Uscito. Per favore</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>accedi</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Aggiungi un account</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Aggiorna</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Condividi %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Inserisci il nome del gruppo</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Inserisci nome utente e password</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Aggiornato con successo </translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Rimosso con successo</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Inserisci il nome utente</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Inserisci il nome del gruppo</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>Nessun gruppo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Già condiviso con %1</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Già condiviso con l&apos;utente %1</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>L&apos;operazione precedente è ancora in corso</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Condividi con:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Condividi</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Permessi:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Lettura-Scrittura</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>In sola lettura</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Chiudi</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>sincronizzato</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indicizzazione dei documenti</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>inizializzazione sincronizzazione</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>scaricamento</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>caricamento</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>fusione sincronia</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>in attesa di sincronizzazione</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>server non connesso</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>autenticazione del server</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>sincronizzazione automatica disattivata</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>sconosciuto</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Il server è stato rimosso</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Non ti sei autenticato nel server</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Non hai i permessi per accedere a questa libreria</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Lo spazio di archiviazione del proprietario della libreria è esaurito</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Servizio remoto non disponibile</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Accesso negato al servizio</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Dati interni corrotti</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Fallito avvio upload</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Fallito avvio download</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Libreria danneggiata sul server</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Conflitto durante l&apos;unione</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>La versione del server è troppo vecchia </translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Errore sconosciuto</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Errore di rete</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>Impossibile risolvere l&apos;indirizzo del proxy</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>Impossibile risolvere l&apos;indirizzo del server</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>Impossibile connettersi al server</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Errore del Server</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Richiesta errata</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>Memoria insufficiente </translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>Limite spazio disponibile raggiunto</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>La liberia è stata cancellata sul server</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>Libreria danneggiata sul server</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Lo spazio di archiviazione è esaurito.</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Errore interno del server</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Il tuo client %1 è troppo vecchio</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Fallita la sincronia di questa libreria</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>File bloccato da un altro programma </translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>La liberia è stata cancellata sul server</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Errore durante l&apos;accesso della cartella locale</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>inizializzazione...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>Impossibile indicizzare i file locali</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>Impossibile controllare le informazioni del server</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>Impossibile creare i file in locale.</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>Impossibile unire le modifiche al file locale</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Password incorretta. Per favore scaricarlo di nuovo</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Errore interno</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>connessione al server...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indicizzazione dei documenti...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Scarico la lista dei file...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Scaricamento dei file...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Creazione cartella...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Unisci i cambiamenti del file..</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Fatto</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>Controllo informazioni del server...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Cancellazione</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Cancellato</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>Errore SSL</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Errore di Rete: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Errore del Server</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>Fallita apertura del database certs</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>Il file &quot;%1&quot; non esiste all&apos;interno di &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 impossibile trovare un&apos;applicazione per aprire il file %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Creata la libreria &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Cancellata la libreria &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Rinomina %1 come</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Impossibile scaricare &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>copia fallita</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Aggiunto</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Cancellato</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Rimosso</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Modificato</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Rinominato</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Aggiunto o modificato</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Spostato</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Cartella aggiunta</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Cartella rimossa</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Cartella rinominata</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Cartella spostata</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>file</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>percorsi</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>e %1 di più</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Riporta lo stato della libreria a</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Riportato il file &quot;%1&quot; allo stato %2</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Recuperata la directory cancellata</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Modificato il nome della libreria o la descrizione</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Un attimo fa</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1 giorno fa</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 giorni fa</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1 ora fa</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 ore fa</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1 minuto fa</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 minuti fa</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Not Part of Certificate&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Sincronizza questa libreria in:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Sincronizza questa cartella in:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Cartella</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Cartella in sola lettura</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Documento</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>Documento PDF</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Immagine</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Documento di Testo</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>File Audio</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>File Video</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Documento Word</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>Documento PowerPoint</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Documento Excel</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>caricamento della lista file</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>File bloccato da un altro programma </translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>Cartella bloccata da un altro programma </translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>File bloccato da un altro utente</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>Percorso non valido</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Errore durante l&apos;indicizzazione</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>Il percorso termina con uno spazio o una virgola</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>il percorso contiene caratteri non validi come &apos;|&apos; o &apos;:&apos;</translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation>Errore nell&apos;apertura del database della cache</translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation>il percorso contiene caratteri non validi come &apos;|&apos; o &apos;:&apos;</translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>Il file non esiste</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Libreria &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Questa libreria non è ancora stata scaricata</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Errore:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>ogni %1 secondi</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>RepoIcon</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>RepoName</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Etichetta di Testo</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Proprietario:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Ultima Modifica:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Dimensione:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Percorso Locale:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Stato:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>RepoStatus</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nome:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Intervallo di sincronizzazione:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Chiuso</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Questa libreria non è stata scaricata</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Aggiornamenti Recenti</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Le mie Librerie</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Sotto Libreria</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Condivise con me</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Condivise con tutti</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Condivise con il gruppo</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Librerie Sincronizzate</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>Avvio sincronizzazione</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Disabilita sincronizzazione automatica</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Abilita sincronizzazione automatica</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Mostra &amp;dettagli</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Mostra dettagli di questa libreria</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Sincronizza questa libreria</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Sincronizza questa libreria</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Aggiornamenti Recenti</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Sincronizza &amp;adesso</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Sincronizza questa libreria immediatamente</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Cancella download</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Cancella download di questa libreria</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Apri cartella</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>apri cartella locale</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Desincronizza</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>desincronizza questa libreria</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Visualizza sul server</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>visualizza questa libreria su seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Condividi con l&apos;utente</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Condividi questa libreria con un utente</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Condividi con un gruppo</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Condividi questa libreria con un gruppo</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Open vista file in cloud</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>&amp;Leave condivisione</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>lascia la condivisione</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Sincronizza questa libreria</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>de-sincronizza e ri-sincronizza questa libreria</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Fallita desincronizzazione libreria &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation>Impossibile lasciare la condivisione</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Fallita la cancellazione di questo task:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Questo download è stato cancellato</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Non hai i permessi per caricare in questa cartella</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>Impossibile sovrascrivere il file &quot;%1&quot; con se stesso</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Impossibile cancellare il file &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Impossibile caricare il file: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Intervallo di sincronizzazione (in secondi):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Imposta intervallo di sincronizzazione per la libreria &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>Cerca librerie</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>riprova</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Tentativo fallito di ottenere informazioni delle librerie&lt;br/&gt;Per favore %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Attenzione:&lt;/b&gt; Il certificato ssl di questo server non è affidabile, procedere comunque?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>Impossibile aggiungere l&apos;account predefinito</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Fallita inizializzazione log: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Si</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annulla</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>%1 Link Interno</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copia negli appunti</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Errore sconosciuto</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Disabilita sincronizzazione automatica</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Abilita sincronizzazione automatica</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Quit</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Mostra finestra principale</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Impostazioni</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Apri %1 &amp;folder</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>apri la cartella %1</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Apri la cartella dei log</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>Mostra errori sincronizzazione</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Informazioni</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Mostra il box About</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Guida in linea</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>File</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>la sincronizzazione automatica è disabilitata</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Caricando</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Scaricando</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>apri la cartella log %1</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>apri la guida in linea di %1</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>alcuni server non sono connessi</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Carica file di log</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>carica il file di log %1</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>Per favore prima effettua l&apos;accesso</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Show nella cartella</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Mostra nella cartella</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>Cerca file</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>riprova</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Impossibile cercare &lt;br/&gt; prego %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Stato di connessione dei server</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>connesso</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>disconnesso</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Chiudi</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Prego, inserire la password della libreria</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Inserisci la password per la libreria %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Prego, inserisci la password</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Password non corretta</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Errore sconosciuto</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Finestra</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annulla</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Impostazioni</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>Avvia automatico %1 dopo il login</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>Nascondi l&apos;icona di %1 dal dock</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Nessuno</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>Proxy HTTP</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Proxy Socks5</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Proxy di sistema</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Hai modificato la lingua. Vuoi riavviare per applicare?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>L&apos;indirizzo del proxy non può essere vuoto</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>La porta del proxy non è corretta</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>L&apos;utente del proxy non può essere vuoto</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>La password del proxy non può essere vuota</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Nascondi la finestra principale dopo l&apos;avvio</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Notifica quando le librerie sono sincronizzate</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Abilita la sincronizzazione dei file temporanei di MSOffice/Libreoffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Velocità massima di download (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Velocità massima di caricamento (kB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Base</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Non desincronizzare automaticamente una libreria</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Non desincronizzare automaticamente una libreria quando la sua cartella locale è rimossa o non accessibile per altre ragioni.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Non sincronizzare una libreria quando non nel server</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Non desincronizzare una libreria quando non presente nel server</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Abilita l&apos;estensione FinderSync</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Abilita l&apos;estensione di Esplora Risorse</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>controlla aggiornamenti automaticamente </translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Non verificare il certificato ssl del server</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Avanzato</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Lingua (richiede riavvio)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Lingua</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Tipo di Proxy:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Host:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Porta:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Nome Utente:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Password:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Il server proxy richiede una password </translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Rete</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancella</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Lettura-Scrittura</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>In sola lettura</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Rimuovi Condivisione</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>Click per modificare</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Creato da %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Lettura-Scrittura</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>In sola lettura</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Gruppo</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Utente</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Permessi</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>L&apos;operazione precedente è ancora in corso</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Condividi Link</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Condividi Link:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Download Diretto</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copia negli appunti</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Connessione Non Affidabile</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 utilizza un certificato di sicurezza non valido. La connessione potrebbe essere insicura. Vuoi continuare?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Il fingerprint della chiave corrente RSA è %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Il fingerprint della chiave RSA precedente è %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Ricorda la mia scelta</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sì</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Apri</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Apri questo file</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>Visualizza sul &amp;Web</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>vedi questo file sul sito</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>riprova</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Tentativo fallito di ottenere informazioni dei preferiti&lt;br/&gt;Per favore %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Non hai nessun file preferito.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Errore Sincronizzazione File</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>Nessun errore di sincronizzazione. </translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Doppio click per aprire la libreria</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Libreria</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Percorso</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Errore</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Tempo</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation>Inserire chiave per autenticazione a due fattori</translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation>Autenticazione a due fattori</translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation>Inserire chiave per autenticazione a due fattori</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mText</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>Ricorda questo dispositivo</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annulla</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Disinstalla %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Vuoi elimiare le informazioni dell&apos;account %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Eliminazione delle informazioni dell&apos;account...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>testo</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sì</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>No</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_ja.ts b/i18n/seafile_ja.ts
new file mode 100644 (file)
index 0000000..7ac2d07
--- /dev/null
@@ -0,0 +1,3286 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="ja" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>アカウントデータベース接続に失敗しました</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>承認タイムアウト、再ログインしてください</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>アカウント設定</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>サーバーアドレスを入力してください</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1のサーバーアドレスは正しくありません</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>アカウント情報の保存に失敗しました</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>%1の情報の保存に失敗しました</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>アカウント情報を保存しました</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>サーバーアドレス</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>メール</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>キャンセル</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>%1アカウントのライブラリ同期解除に失敗しました</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>クリックでウェブサイトが開きます</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>Pro版</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>アカウント無し</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>アカウント設定</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>アカウントを追加</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>ログアウト</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>ログインはまだ</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>フォーム</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>アカウント</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>メール</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>サーバ</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>再実行</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>アップロード完了</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>ファイル%1
+アップロード完了しました。</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>ファイル%1
+アップロード失敗しました。</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>プロフィール画像フォルダ作成に失敗しました</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>ダウンロード・ジョブ</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>完了したジョブを削除</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>今はダウンロードをしない。</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>クリア</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>閉じる</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>ライブラリ</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>パス</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>ジョブをキャンセル</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>ジョブをキャンセル</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>ジョブを削除</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>ジョブのキャンセルに失敗しました:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>ジョブの削除に失敗しました:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>最小にする</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>閉じる</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>ライブラリ</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>同期フォルダを選択してください</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>フォーム</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>ロゴ</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>最小にする</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>閉じる</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>選択</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>ccnet設定でエラーが発生しました</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>ディレクトリを選択してください</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>同期ディレクトリを選択してください</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>名前を入力してください</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>パスワードを入力してください</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>パスワードが一致しません</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>不明なエラー</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>ダウンロードジョブの追加に失敗しました:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>パス:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>選択してください</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>名称:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>パスワード:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>パスワード確認:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>キャンセル</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>パスワードを入力してください</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>フォルダを選択してください</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>同期フォルダを選択してください</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>ダウンロードジョブの追加に失敗しました:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>選択してください</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>ライブラリのパスワード:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>キャンセル</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>変更詳細</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>クラウドファイル表示</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>戻る</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>進む</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>ホーム</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>ファイルをアップロード</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>ディレクトリをアップロード</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>フォルダを作成</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>フォルダ名</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>正しくないフォルダ名</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>再実行</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>%1ファイルが既にあります。&lt;br/&gt;上書きして宜しいですか?&lt;br/&gt;&lt;small&gt;(別名でアップロードする場合には「いいえ」を選択してください).。&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>アップロードファイルを選択してください</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>アップロードディレクトリを選択してください</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>キャンセル</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>アップロード</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>アップロード中 %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>ダウンロード</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>ダウンロード中 %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>処理がキャンセルされました</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>サーバ内部エラー</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>名称</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>サイズ</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>名前付け保存(&amp;s)</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>名前変更(&amp;r)</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>削除(&amp;d)</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>更新(&amp;u)</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>コピー(&amp;c)</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>カット(&amp;t)</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>ペスト(&amp;p)</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>ダウンロードキャンセル(&amp;e)</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>フォルダ同期(&amp;s)</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>この機能はPro版のみで利用可能です
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>ディレクトリを選択してください</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>ロゴ</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>選択してください</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>次</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>キャンセル</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>デフォルト・ライブラリをダウンロード中にエラーが発生しました:%1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>はい</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>ロゴ</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>ネットワークエラー:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>ユーザー名を入力してください</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>コンピュータ名を入力してください</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>パスワードを入力してください</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>メールアドレスまたはパスワードが正しくありません</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>サーバ内部エラー</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>ロゴ</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>パスワード:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>コンピュータ名:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>キャンセル</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>不明なエラー</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>サーバ内部エラー</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>ローカル・フォルダでエラーが発生しました</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>キャンセル中</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>キャンセルしました</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSLエラー</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>ネットワークエラー:%1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>サーバエラー</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>ファイル</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>只今</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1日前</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1日前</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1時間前</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1時間前</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1分前</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1分前</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Not Part of Certificate&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>フォルダー</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>ドキュメント</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF・ドキュメント</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>映像ファイル</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>テキスト・ドキュメント</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>音声ファイル</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>動画ファイル</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>ワード・ドキュメント</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>パワーポイント・ドキュメント</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>エクセル・ドキュメント</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>無効なパス</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot;ライブラリ</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>エラー:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>リポジトリ名</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>ローカルパス</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>名称:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>閉じる</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>同期(&amp;n)</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>ダウンロードをキャンセル(&amp;c)</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>ライブラリのダウンロードをキャンセル</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>ジョブのキャンセルに失敗しました:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>ダウンロードがキャンセルされました</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>不明なエラー</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>閉じる</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>ライブラリのパスワードを入力してください</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>%1ライブラリのパスワードを入力してください</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>パスワードを入力してください</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>パスワードが正しくありません</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>不明なエラー</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>キャンセル</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>なし</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>ユーザー名:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>パスワード:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>プロクシパスワードを入力してください。</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>キャンセル</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>はい</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>いいえ</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>パーズ</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>エラー</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイアログ</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>はい</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>いいえ</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_ko_KR.ts b/i18n/seafile_ko_KR.ts
new file mode 100644 (file)
index 0000000..36a8011
--- /dev/null
@@ -0,0 +1,3308 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="ko_KR" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>%1 정보</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 클라이언트 %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; 리비전 %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>정보</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>업데이트 확인</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>확인</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>계정 데이터베이스 열기에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>인증 유효시간이 지났습니다. 다시 로그인하세요</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation>로컬 저장소 동기화 토큰 제거에 실패했습니다: %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation>서버에서 저장소 동기화 정보 가져오기에 실패했습니다: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>계정 설정</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>서버 주소를 입력해주세요</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 서버 주소가 올바르지 않습니다</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>계정 정보 저장에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>바뀐 내용 저장에 실패했습니다: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>현재 계정 정보 업데이트에 성공했습니다</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>서버 주소</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>전자메일</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>확인</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>%1 계정을 정말 제거할까요?&lt;br&gt;&lt;br&gt;로컬 계정만 삭제합니다. 모든 동기화 정보도 함께 삭제합니다. 서버 계정에는 영향을 주지 않습니다.</translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>이 계정의 라이브러리 동기화 해제에 실패했습니다: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>웹 사이트를 열려면 클릭하세요</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>전문가 버전</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>계정 없음</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>선택</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>계정 설정</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>로그인</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>삭제</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>계정 추가</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>로그아웃</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>로그인 안 함</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>양식</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>계정</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>전자메일</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>서버</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>파일 활동은 %1 서버 전문가 판에서만 지원합니다.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>다시 시도</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>활동 정보 가져오기에 실패했습니다. %1 해주세요</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>업로드 성공</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>&quot;%1&quot; 파일 
+업로드에 성공했습니다.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>&quot;%1&quot; 파일
+업로드에 실패했습니다.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>권한 오류!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>인증 유효 시간이 지났습니다.</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>파일이 없습니다</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation>%1이(가) 파일을 잠궜습니다. 나중에 다시 시도하세요</translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>업로드 실패: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>아바타 폴더 만들기에 실패했습니다</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>권한 검사 중</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>다운로드 작업</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>성공한 모든 작업 제거</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>현재 다운로드 작업이 없습니다.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>지우기</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>닫기</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>라이브러리</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>경로</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>이 작업 취소</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>이 작업 취소</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>이 작업 제거</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>이 작업 취소에 실패했습니다:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>이 작업 제거에 실패했습니다:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>최소화</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>닫기</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>라이브러리</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>별표 표시함</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>활동</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>검색</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>현재 다운로드율</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>현재 업로드율</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>동기화할 폴더를 선택해주세요</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>연결한 서버 없음</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>모든 서버에 연결했습니다</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>일부 서버에 연결하지 않았습니다</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>양식</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>로고</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>최소화</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>닫기</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>선택</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>브랜드</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>하거나 폴더를 내려놓아 동기화하세요</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>다운로드율</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>아래 화살표</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>업로드율</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>위 화살표</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>ccnet 설정을 만드는데 오류가 있습니다</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>미리 설정한 &quot;%1&quot; 디렉터리를 만들 수 없습니다</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>%1 읽기 실패</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>라이브러리 만들기</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>디렉토리를 선택해주세요</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>만드는 중...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>이 라이브러리의 암호화 키 생성에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>동기화 할 디렉토리를 선택해주세요</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>%1 폴더가 없습니다</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>이름을 입력해주세요</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>암호를 입력해주세요</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>암호가 일치하지 않습니다</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>알 수 없는 오류</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>다운로드 작업 추가에 실패했습니다:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>서버에 라이브러리 만들기에 실패했습니다:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>경로:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>선택</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>이름:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>암호화</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>암호:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>암호 다시입력:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>상태 텍스트</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>확인</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>%1 클라이언트 초기화에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>예상치 못하게 %1(에)서 빠져나왔습니다</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>암호를 입력해주세요</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 라이브러리 동기화</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 동기화 폴더</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>이 폴더에 동기화:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>또는</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>기존 폴더와 동기화</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>새 동기화 폴더 만들기</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>다음 기존 폴더와 동기화:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>폴더를 선택하세요</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>폴더가 없습니다</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>동기화할 폴더를 선택하세요</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>%1 폴더 밖으로의 라이브러리 위치는 금지되어 있습니다.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>기존의 &quot;%1&quot; 파일이 이미 있습니다. 다른 폴더를 선택하세요.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>기존의 &quot;%1&quot; 라이브러리가 이미 있습니다. 다른 폴더를 선택하세요.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>&quot;%1&quot; 폴더가 이미 있습니다. 정말로 이 폴더를 동기화(내용 병합)할까요?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>아니요를 누르면 새 폴더로 동기화합니다</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>다른 폴더 이름을 찾을 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>다운로드 작업 추가에 실패했습니다:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>저장소 다운로드 정보 가져오기에 실패했습니다:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>라이브러리 다운로드</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>선택...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>이 라이브러리 암호:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>확인</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>자세한 수정 내용</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>추가한 파일</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>삭제한 파일</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>수정한 파일</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>추가한 폴더</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>삭제한 폴더</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>열기(&amp;O)</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>상위 폴더 열기(&amp;P)</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>클라우드 파일 브라우저</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>뒤로</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>앞으로</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>처음</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>파일 업로드</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>디렉터리 업로드</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>이 라이브러리에 파일을 업로드할 권한이 없습니다</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>폴더 만들기</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>새로 고침</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>항목 %1개</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>폴더 이름</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>잘못된 폴더 이름입니다!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>&quot;%1&quot; 이름을 가진 객체가 있습니다.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>다시 시도</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>파일 정보 가져오기에 실패했습니다&lt;br/&gt;
+%1 해주세요</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>이 폴더는 비어있습니다.</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>저장할 파일 이름을 입력하세요...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 파일을 제거할 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>저장하려는 폴더 경로를 입력하세요...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>기존의 &quot;%1&quot;  파일을 덮어쓸까요?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>&quot;%1&quot; 파일은 동기화하지 않았습니다</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>%1 파일이 존재합니다.&lt;br/&gt;덮어쓸까요?&lt;br/&gt;&lt;small&gt;(다른 이름으로 업로드하려면 아니요를 선택하세요).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>파일이 없습니다</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>파일 다운로드에 실패했습니다: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>업로드할 파일을 선택하세요</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>업로드할 디렉터리를 선택하세요</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>이름 바꾸기</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>이 항목을 정말로 삭제할까요?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>폴더 만들기 실패</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>파일 잠금 실패</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>%1을(를) 업데이트할 파일을 선택하세요</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>이름 바꾸기에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>제거에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>공유에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>동일한 폴더에 파일을 붙여넣을 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>폴더를 자체 하위 폴더로 붙여넣을 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>복사 실패</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>이동 실패</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>라이브러리 만들기에 실패했습니다!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>이 폴더에 업로드할 권한이 없습니다</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>인증 유효 시간이 지났습니다.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>권한 오류!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>라이브러리/폴더가 없습니다.</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation>%1 파일 업로드에 실패했습니다: %2</translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation>캐시 폴더를 만들 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation>캐시 폴더를 열 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>파일 검색</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation>링크 가져오기에 실패했습니다</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>대기 중</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>업로드</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>%1 업로드 중</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>다운로드</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>%1 다운로드 중</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%2 중 %1</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>&quot;%1&quot; 파일 업로드에 실패했습니다. 다시 시도해볼까요?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>다시 시도</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>건너뛰기</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>중단</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>저장 중</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>파일 저장에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>이름</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>크기</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>마지막 수정</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>폴더에 표시(&amp;S)</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>폴더에 표시</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>동작을 취소했습니다</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>기다리는 중</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>작업을 취소했습니다</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>내부 서버 오류</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>제한 저장 공간을 모두 채웠습니다</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>%1이(가) 잠금</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>이름 </translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>크기</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>마지막 수정</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation>수정자</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>다른 이름으로 저장(&amp;S)...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>잠금(&amp;L)</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>제거(&amp;R)</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>삭제(&amp;D)</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>그룹에 공유</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>업데이트(&amp;U)</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>복사(&amp;C)</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>잘라내기(&amp;T)</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>붙여넣기(&amp;P)</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>다운로드 취소(&amp;E)</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>이 폴더 동기화(&amp;S)</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>이 기능은 전문가 버전에서만 사용할 수 있습니다
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>%1 다운로드 링크 만들기(&amp;G)</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>사용자에게 공유</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>%1 내부 링크 만들기(&amp;E)</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>다음 경로에 다른 이름으로 저장(&amp;S)...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>잠금 해제(&amp;L)</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>읽기 전용 파일을 제거할 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>읽기 전용 파일을 잘라낼 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>업로드 다시 시도</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>로컬 버전 삭제</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>로컬 버전을 다른 이름으로 저장...</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation>로컬 캐시 폴더 열기</translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation>링크 가져오기에 실패했습니다</translation>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>폴더 만들기에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>임시 파일 만들기에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>디스크로의 파일 기록에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>다운로드한 파일의 이전 버전 삭제에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>파일 이동에 실패했습니다</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 초기화</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>%1 폴더 선택</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>디렉토리를 선택해주세요</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>초기화를 끝내지 않았습니다. 정말 빠져나갈까요?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>%1 폴더가 없습니다</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>로고</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>폴더 선택</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>폴더를 선택하세요. %1 하위 폴더를 만들겠습니다. 라이브러리를 다운로드하면 기본으로 해당 위치에 저장합니다.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>선택...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>다음</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1 에서 라이브러리로 파일을 모아둡니다.
+기본 라이브러리를 다운로드할까요?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>기본 라이브러리 확인 중...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>기본 라이브러리 만드는 중...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>기본 라이브러리 만들기에 실패했습니다:
+
+이를 지원하려면 서버버전은 2.1 이상이어야 합니다.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>기본 라이브러리 가져오기에 실패했습니다:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>기본 라이브러리 만들기에 실패했습니다:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>기본 라이브러리 다운로드 중...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>기본 라이브러리 다운로드에 실패했습니다:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>기본 라이브러리를 다운로드했습니다.
+&quot;열기&quot;버튼을 눌러 다운로드한 내용을 보실 수 있습니다.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>기본 라이브러리 다운로드 중 오류: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>기본 라이브러리 다운로드에 실패했습니다:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1 에서 라이브러리로 파일을 모아둡니다.
+기본 라이브러리를 다운로드할까요?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>건너뛰기</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>백그라운드에서 실행</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>열기</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>끝내기</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>기본 라이브러리 다운로드</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>예</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>로고</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>더 불러오기</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>실패 로그 파일 업로드</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>로그 파일 업로드</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>권한 오류!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>라이브러리/폴더가 없습니다.</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>인증 유효 시간이 지났습니다.</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>로그 파일 업로드 실패: %1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>로그 파일 업로드에 성공했습니다</translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>압축 중</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%2 중 %1</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>계정 추가</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>단일 로그온</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>다시 로그인</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>로그인 중...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>네트워크 오류:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;경고:&lt;/b&gt; 이 서버의 ssl 인증서를 믿을 수 없습니다, 그래도 진행할까요?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>서버 주소를 입력해주세요</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 서버 주소가 올바르지 않습니다</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>사용자 이름을 입력해주세요</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>컴퓨터 이름을 입력해주세요</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>현재 계정 저장에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1 서버 주소</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>서버 주소를 비워둘 수 없습니다</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1은(는) 올바른 서버 주소가 아닙니다. &apos;https://&apos;로 시작해야 합니다</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>암호를 입력해주세요</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>전자메일 주소 또는 암호가 틀렸습니다</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>로깅을 너무 자주 합니다, 잠시만 기다려주세요</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>내부 서버 오류</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>로그인 실패: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>로그인에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>로고</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>서버:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;예: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>또는 http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>암호:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>상태 텍스트</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>컴퓨터 이름:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>전자메일 / 사용자 이름</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>e.g. 철수의 랩톱</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>로그인</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>자동 로그인</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>로그아웃 했습니다.</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>로그인해주세요</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>계정 추가</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>새로고침</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation>&quot;%1&quot; 동기화를 취소했습니다.
+이유: 서버에서 삭제함</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation>&quot;%1&quot;을(를) 동기화했습니다.</translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation>&quot;%1&quot;에 파일을 업로드했습니다</translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation>%1 파일 중복</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation>%1 파일 동기화에 실패했습니다
+다른 프로그램에서 파일을 잠궜습니다. 프로그램을 닫으면 이 파일을 업데이트합니다.</translation>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation>%1 폴더 동기화에 실패했습니다
+폴더의 일부 파일을 다른 프로그램에서 잠궜습니다. 프로그램을 닫으면 이 폴더를 업데이트합니다.</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation>%1 파일 동기화에 실패했습니다
+다른 사용자가 파일을 잠궜습니다. 이 파일의 최신 버전을 업로드하지 않았습니다.</translation>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation>%1 파일 인덱싱에 실패했습니다.
+파일 권한과 디스크 공간을 확인하세요.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation>%1 동기화에 실패했습니다
+파일 경로끝에 공백 문자 또는 구두점이 있으며, 윈도우에서 만들 수 없습니다.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation>%1 동기화에 실패했습니다
+파일 경로에 부적절한 문자가 있습니다. 이 컴퓨터에 동기화하지 않습니다.</translation>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation>폴더 권한 설정에 따라 %1 파일 업데이트를 거부합니다.</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation>&quot;%1&quot; 동기화에 실패했습니다.
+서비스에 접근할 수 없습니다</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation>&quot;%1&quot; 동기화에 실패했습니다.
+라이브러리 사용자 저장 공간이 다 찼습니다.</translation>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>%1 공유</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>그룹 이름을 입력하세요</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>사용자 이름 또는 전자메일 주소를 입력하세요</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>성공적으로 업데이트했습니다</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>공유 처리에 실패했습니다: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>성공적으로 제거했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>폴더의 공유 정보 가져오기에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>그룹 및 연락처 정보 가져오기에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>사용자 이름을 입력하세요</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>그룹 이름을 입력하세요</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 그룹이 없습니다</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>%1 그룹에 이미 공유했습니다</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>%1 사용자에게 이미 공유했습니다</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>이전 처리를 여전히 진행중입니다</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>공유 대상:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>공유</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>권한:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>읽기-쓰기</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>읽기 전용</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>닫기</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>동기화 함</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>파일 색인 중</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>동기화 초기화 중</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>다운로드 중</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>업로드 중</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>동기화 병합 중</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>동기화 기다리는 중</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>연결한 서버가 없습니다.</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>서버 인증 중</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>자동 동기화를 껐습니다</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>알 수 없음</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>서버를 제거했습니다</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>서버에 로그인하지 않았습니다</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>이 라이브러리에 접근할 권한이 없습니다.</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>라이브러리 소유자의 저장 공간이 꽉 찼습니다</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>원격 서비스를 사용할 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>서비스 접근이 거부되었습니다</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>내부 데이터가 깨졌습니다</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>업로듯 시작에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>다운로드 시작에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>서버의 라이브러리가 깨졌습니다</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>병합 충돌</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>서버 버전이 너무 오래되었습니다</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>알 수 없는 오류</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>네트워크 오류</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>프록시 주소를 해석할 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>서버 주소를 해석할 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>서버에 연결할 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>보안 연결에 실패했습니다. 서버 SSL 인증서를 확인하세요</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation>데이터 전송을 멈췄습니다. 네트워크 또는 방화벽을 확인하세요</translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation>데이터 전송 시간을 초과했습니다. 네트워크 또는 방화벽을 확인하세요</translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation>서버에서 처리할 수 없는 http 경로 변경. 서버 설정을 확인하세요</translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>서버 오류</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>잘못된 요청</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>메모리 부족</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation>클라이언트 데이터 기록에 실패했습니다. 디스크 공간 또는 폴더 권한을 확인하세요</translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>저장 공간이 찼습니다</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>서버의 라이브러리를 삭제했습니다</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>서버의 라이브러리가 깨졌습니다</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>저장공간 제한을 채웠습니다</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>내부 서버 오류</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>%1 클라이언트가 상당히 오래되었습니다</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>이 라이브러리 동기화에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>다른 프로그램에서 파일을 잠궜습니다</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>라이브러리를 서버에서 삭제했습니다</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>로컬 폴더 접근 중 오류가 있습니다</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>초기화 중...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>로컬 파일 인덱싱에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>서버 정보 확인에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>로컬 파일 만들기에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>바뀐 로컬 파일 병합에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>잘못된 암호입니다. 다시 다운로드해주세요</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>내부 오류</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>서버에 연결 중...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>파일 색인 중</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>파일 목록 다운로드 중...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>파일 다운로드 중...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>폴더 만드는 중...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>바뀐 파일 병합 중...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>완료</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>서버 정보 확인 중...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>취소 중</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>취소함</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL 오류</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>네트워크 오류: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>서버 오류</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>cert 데이터베이스 열기에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>&quot;%2&quot;에 &quot;%1&quot; 파일이 없습니다</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1이(가) %2 파일을 열 프로그램을 찾을 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 라이브러리를 만들었습니다</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 라이브러리를 삭제했습니다</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>%1 이름 바꾸기:</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 항목을 다운로드할 수 없습니다</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>복사에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>추가함</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>삭제함</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>제거함</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>수정함</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>이름 바꿈</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>추가 또는 수정함</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>이동함</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>추가한 디렉터리</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>제거한 디렉터리</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>이름 바꾼 디렉터리</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>이동한 디렉터리</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>파일</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>디렉터리</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>및 추가 %1개 </translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>다음 시간의 상태로 라이브러리 복원:</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>&quot;%1&quot; 파일을 %2의 상태로 복원했습니다.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>삭제한 디렉터리를 복구했습니다</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>라이브러리 이름 또는 설명을 바꾸었습니다</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>%1 시스템에서 자동으로 병합</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>방금</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1일 전</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1일 전</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1시간 전</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1시간 전</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1분 전</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1분 전</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Not Part of Certificate&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>이 라이브러리 동기화 대상:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>이 폴더 동기화 대상:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>폴더</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>읽기 전용 폴더</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>문서</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF 문서</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>그림 파일</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>텍스트 문서</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>오디오 파일</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>동영상 파일</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>워드 문서</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>파워포인트 문서</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>엑셀 문서</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>&quot;%1&quot; 경로가 시스템 경로와 충돌합니다</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>&quot;%1&quot; 경로가 기존 라이브러리와 충돌합니다</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>파일 목록 업로드 중</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>다른 프로그램에서 파일을 잠궜습니다</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>다른 프로그램에서 폴더를 잠궜습니다</translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>다른 사용자가 파일을 잠궜습니다</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>잘못된 경로</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>인덱싱 오류</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>경로 끝에 공백 또는 마침표가 있습니다</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>경로에 &apos;|&apos; 또는 &apos;;&apos;  같은 잘못된 문자가 있습니다</translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation>파일 캐시 데이터베이스 열기에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation>&apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos; 같은 잘못된 문자가 라이브러리 이름에 있습니다</translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation>폴더 권한 설정에 따라 파일 업데이트를 거부합니다</translation>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation>%1 클라이언트를 이미 실행 중입니다</translation>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation>업로드 오류 발생</translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation>다운로드 오류 발생</translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation>서버에서 권한을 거부했습니다. 라이브러리를 다시 동기화해보세요</translation>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation>클라이언트 내부 데이터가 깨졌습니다. 라이브러리를 다시 동기화해보세요</translation>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation>라이브러리 기록 권한이 없습니다</translation>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation>라이브러리 동기화 권한이 없습니다</translation>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation>이 폴더를 동기화할 권한이 없습니다</translation>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>파일이 없습니다</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 라이브러리</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>이 라이브러리를 아직 다운로드하지 않았습니다</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>오류:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>%1 초 마다</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>저장소 아이콘</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>저장소 이름</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>텍스트 레이블</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>소유자:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>최종 고침:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>크기:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>로컬 경로:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>상태:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>저장소 상태</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>이름:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>동기화 시간 간격:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>닫기</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>이 라이브러리는 다운로드하지 않았습니다</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>없는 &quot;%2&quot; 라이브러리의 &quot;%1&quot; 파일을 열 수 없습니다</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>최근 업로드</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>내 라이브러리</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>하위 라이브러리</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>나에게 공유</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>모두에게 공유</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>그룹에 공유</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>동기화한 라이브러리</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>동기화 초기화 중</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>자동 동기화 비활성화</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>자동 동기화 활성화</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>세부 정보 표시(&amp;D)</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>이 라이브러리 세부 정보 표시</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>이 라이브러리 동기화(&amp;S)</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>이 라이브러리 동기화</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>최근 업데이트 항목</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>지금 동기화(&amp;N)</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>이 라이브러리 바로 동기화</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>다운로드 취소(&amp;C)</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>이 라이브러리 다운로드 취소</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>폴더 열기(&amp;O)</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>로컬 폴더 열기</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>로컬 폴더 열기(&amp;O)</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>동기화 해제(&amp;U)</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>이 라이브러리 동기화 해제</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>클라우드에서 보기(&amp;V)</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>시허브에서 이 라이브러리 보기</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>사용자에게 공유</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>이 라이브러리를 사용자에게 공유합니다</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>그룹에 공유</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>이 라이브러리를 그룹에 공유합니다</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>클라우드 파일 브라우저 열기(&amp;O)</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>내장 클라우드 파일 브라우저에서 이 파일을 엽니다</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>공유 항목에서 나가기(&amp;L)</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>공유 항목에서 나가기</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>이 라이브러리 다시 동기화(&amp;R)</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>이 라이브러리 동기화를 해제하고 다시 동기화합니다</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>동기화 시간 간격 설정(&amp;I)</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation>이 라이브러리 동기화 주기 설정</translation>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation>&quot;%1&quot; 라이브러리 동기화를 해제할까요?</translation>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation>&quot;%1&quot; 라이브러리를 다시 동기화할까요?</translation>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 파일을 덮어쓸까요?</translation>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 라이브러리 동기화 해제에 실패했습니다.</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation>&quot;%1&quot; 공유에서 나갈까요?</translation>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation>공유 항목에서 나가기에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>이 작업 취소에 실패했습니다:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>다운로드를 취소했습니다.</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>이 폴더에 업로드할 권한이 없습니다</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>&quot;%1&quot; 파일 자체에 덮어쓸 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 파일을 삭제할 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>파일 업로드에 실패했습니다: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>동기화 시간 간격(초 단위):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; 라이브러리 동기화 시간 간격을 설정합니다</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>라이브러리 검색</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>다시 시도</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>라이브러리 정보를 가져오는데 실패했습니다&lt;br/&gt;%1 해주세요</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;경고:&lt;/b&gt; 이 서버의 ssl 인증서를 믿을 수 없습니다, 그래도 진행할까요?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>기본 계정 추가에 실패했습니다</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>로그 초기화에 실패했습니다: %1</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>확인</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>예</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>아니요</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation>클라이언트 ID 저장 실패</translation>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation>%1 접근 실패</translation>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation>올바르지 않은 클라이언트 ID</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>%1 읽기 실패</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>%1 내부 링크</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>클립보드로 복사</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>확인</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation>%1 내부 링크:</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>알 수 없는 오류</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation>내부 오류: 데몬 연결 실패</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>자동 동기화 비활성화</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>자동 동기화 활성화</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>끝내기(&amp;Q)</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>메인 창 표시</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>설정</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>%1 폴더 열기(&amp;F)</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>%1  폴더 열기</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>기록 폴더 열기(&amp;L)</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>파일 동기화 오류 표시</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>정보(&amp;A)</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>프로그램 정보 상자 표시</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>온라인 도움말(&amp;O)</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>파일</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>자동 동기화를 비활성화했습니다</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>업로드 중</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>다운로드 중</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>%1 기록 폴더 열기</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>%1 온라인 도움말 열기</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>일부 서버에 연결하지 않았습니다</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>로그 파일 업로드</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>로그 파일 %1개 업로드</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>먼저 로그인 해주세요</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation>탐색기 확장 기능 복원</translation>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>폴더에 표시(&amp;S)</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>폴더에 표시</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>파일 검색</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>다시 시도</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>검색에 실패했습니다.
+%1 해주세요</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>서버 연결 상태</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>연결함</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>연결 끊음</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>닫기</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>라이브러리 암호를 입력해주세요</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>%1 라이브러리의 암호를 입력하세요</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>암호를 입력해주세요</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>올바르지 않은 암호</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>알 수 없는 오류</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화 상자</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>확인</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>설정</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>로그인 후 %1 자동 시작</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>도크에서 %1 아이콘 숨기기</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>없음</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP 프록시</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5 프록시</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>시스템 프록시</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>언어를 바꿨습니다. 다시 시작해서 적용할까요?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>프록시 호스트 주소를 비워둘 수 없습니다</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>프록시 포트가 올바르지 않습니다</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>프록시 사용자 이름을 비워둘 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>프록시 암호를 비워둘 수 없습니다</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>시작할 때 메인 창 숨기기</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>라이브러리를 동기화하면 알림</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>MS 오피스/리브레오피스 임시 파일 동기화 활성화</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>다운로드 속도 제한(KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>업로드 속도 제한(KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>기본</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>자동으로 라이브러리 동기화 해제 안함</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>로컬 디렉터리를 제거했거나 다른 이유로 접근할 수 없을 때 라이브러리를 자동으로 동기화 해제하지 않습니다.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>서버에 라이브러리가 없으면 동기화 해제 안함</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>서버에 라이브러리가 없다면 자동으로 동기화 해제 안함</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>FinderSync 확장 기능 활성화</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>탐색기 확장 기능 활성화</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>업데이트 자동으로 확인</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>HTTPS 동기화시 서버 인증서 검증하지 않음</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>다른 이름을 가진 기존 폴더와 동기화 활성화</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>고급</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>언어(다시 시작해야 함)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>언어</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>프록시 형식:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>호스트:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>포   트:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>사용자 이름:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>암호:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>프록시 서버에 암호가 필요합니다</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>네트워크</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>확인</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>읽기 쓰기</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>읽기 전용</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>공유 항목 제거</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>눌러서 편집</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>%1 사용자가 만듬</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>읽기 쓰기</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>읽기 전용</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>그룹</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>사용자</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>권한</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>이전 진행 작업을 여전히 처리중입니다</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>연결 공유</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>연결 공유:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>직접 다운로드</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>클립보드로 복사</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>확인</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>믿을 수 없는 연결</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1이 잘못된 보안 연결을 사용합니다. 연결이 안전하지 않을 수 있습니다. 계속할까요?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>현재 RSA 지문키는 다음과 같습니다: %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>이전 RSA 지문키는 다음과 같습니다: %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>내 선택 기억</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>예</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>아니요</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>열기(&amp;O)</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>이 파일 열기</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>웹에서 보기(&amp;W)</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>웹 사이트에서 이 파일 보기</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>다시 시도</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>별표 표시한 파일 정보 가져오기에 실패했습니다&lt;br/&gt; %1 해주세요</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>아직 별표 표시한 파일이 없습니다.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>파일 동기화 오류</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>오류 없이 동기화했습니다.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>라이브러리를 열려면 두 번 누르세요</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>라이브러리</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>경로</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>오류</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>시간</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation>이중 인증 토큰을 입력하세요</translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation>이중 인증</translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation>이중 인증 토큰을 입력해주세요</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mText</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>이 장치 기억</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>취소</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>확인</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>%1 설치 제거</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>%1 계정 정보를 제거할까요?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>계정 정보 제거 중...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>대화상자</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>텍스트</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>예</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>아니요</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_lv.ts b/i18n/seafile_lv.ts
new file mode 100644 (file)
index 0000000..7e3f157
--- /dev/null
@@ -0,0 +1,3279 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="lv" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>Par %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>Par</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Meklēt atjauninājumus</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Labi</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>neizdevās atvērt kontu datubāzi</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Konta iestatījumi</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Lūdzu, ievadiet servera adresi</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 nav derīga servera adrese</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Neizdevās saglabāt konta informāciju</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Neizdevās saglabāt izmaiņas: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Veiksmīgi atjaunināta pašreizējā konta informācija</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Servera adrese</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>E-pasts</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Labi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Atcelt</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>pro versija</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Nav konta</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Izvēlēties</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Konta iestatījumi</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Pieslēgties</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Dzēst</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Pievienot kontu</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Atteikties</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Forma</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Konts</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>e-pasts</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>serveris</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>atkārtot</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Augšupielāde veiksmīga</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Lejupielādēt uzdevumus</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Notīrīt</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Aizvērt</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Bibliotēka</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Ceļš</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Atcelt šo uzdevumu</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>atcelt šo uzdevumu</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Dzēst šo uzdevumu</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Neizdevās atcelt šo uzdevumu:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Neizdevās dzēst šo uzdemumu:
+
+ %1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimizēt</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Aizvērt</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Bibliotēkas</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Favorīti</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation> Aktivitātes</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Meklēt</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>pašreizējais lejupielādes ātrums</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>pašreizējais augšupielādes ātrums</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Forma</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>emblēma</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimizēt</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>aizvērt</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Atlasīt</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>lejupielādes ātrums</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>augšupielādes ātrums</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>neizdevās nolasīt %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Izveidot bibliotēku</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Izveido...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Lūdzu, ievadiet vārdu</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Lūdzu, ievadiet paroli</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Paroles nesakrīt</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Nezināma kļūda</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Ceļš: </translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Izvēlēties</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Vārds: </translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>šifrēts</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Parole: </translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Parole vēlreiz: </translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>statusa teksts</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Labi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Atcelt</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Lūdzu, ievadiet paroli</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Sinhronizēt bibliotēku &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Sinhronizēt mapi &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>vai</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Lūdzu, izvēlieties mapi</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>Mape neeksistē</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Lejupielādēt bibliotēku</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>izvēlieties...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Parole šai bibliotēkai:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Labi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Atcelt</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Izmaiņu detaļas</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Pievienot datnes</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Dzēst datnes</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Modificēt datnes</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Pievienot mapes</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Dzēst mapes</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Atvērt</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Atpakaļ</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Uz priekšu</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Mājas</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Augšupielādēt datnes</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Augšupielādēt mapes</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Izveidot mapi</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Atjaunot</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Mapes vārds</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Mapes vārds nederīgs!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>Vārds &quot;%1&quot; ir jau aizņemts.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>atkārtot</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Neizdevās lejupielādēt failu: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Pārdēvēt</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Izveidot mapi neizdevās</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Bloķēt failu neizdevās</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Pārsaukt neizdevās</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Koplietot neizdevās</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Kopēt neizdevās</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Pārvietot neizdevās</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Izveidot bibliotēku neizdevās!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Atcelt</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Augšupielādēt</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Augšupielādē %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Lejupielādēt</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Lejupielādē %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 no %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Operācija atcelta</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>gaida izpildi</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Iekšējā servera kļūda</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>Bloķējis %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Vārds</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Izmērs</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Pēdējoreiz modificēts</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>Pārdēvēt</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>Dzēst</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>Atjaunot</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>Kopēt</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Izgriezt</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>Ielīmēt</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Neizdevās izveidot mapes</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Neizdevās izveidot pagaidu datnes</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Neizdevās ierakstīt datni diskā</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Neizdevās pārvietot datni</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 inicializēšana</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Lūdzu, izvēlieties mapi</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>emblēma</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Izvēlieties mapi</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Izvēlēties...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Nākošais</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Atcelt</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Izlaist</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Izpildīt fonā</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Atvērt</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Pabeigts</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Lejupielādēt noklusēto bibliotēku</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Jā</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>emblēma</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Pievienot kontu</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Piesakos...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Tīkla kļūda:
+ %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Lūdzu, ievadiet paroli</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Iekšējā servera kļūda</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Neizdevās pieteikties: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Neizdevās pieteikties</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>emblēma</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Serveris: </translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Piemēram: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>vai http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Parole: </translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>statusa teksts</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Datora vārds: </translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>E-pasts/Lietotajvārds</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>, piemēram, Džima klēpjdators</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Pieslēgties</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Atcelt</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>pieslēgties</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Pievienot kontu</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Atjaunot</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Koplietot %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Aizvērt</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>lejupielādē</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>augšupielādē</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>nezināms</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Iekšējie dati bojāti</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Nezināma kļūda</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Iekšējā servera klūda</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>inicializēšana...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Izveido mapi...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL kļūda</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Tīkla kļūda: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Servera kļūda</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Izveidota bibliotēka &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Dzēsta bibliotēka &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Pārsaukt %1 uz</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>kopēt neizdevās</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Pievienots</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Dzēsts</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Noņemts</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Modificēts</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Pārdēvēts</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Pārvietots</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Pievienota mape</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Noņemta mape</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Pārsaukta mape</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Pārvietota mape</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>datnes</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>mapes</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>un %1 vairāk</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Tagad</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>Pirms 1 dienas</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>Pirms %1 dienām</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>Pirms 1 stundas</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>Pirms %1 stundām</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>Pirms 1 minūtes</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>Pirms %1 minūtēm</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Not Part of Certificate&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Mape</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Tikai lasāma mape</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Dokuments</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF dokuments</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Attēla datne</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Teksta dokuments</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Audio datne</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Video datne</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Word dokuments</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>PowerPoint dokuments</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Excel dokuments</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Bibliotēka &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Kļūda:  </translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>katras %1 sekundes</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Īpašnieks: </translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Pēdējoreiz modificēts:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Izmērs: </translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Lokālais ceļš: </translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Statuss: </translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Bibliotēkas statuss</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Vārds: </translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Aizvērt</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Manas bibliotēkas</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Apakšbibliotēkas</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>Atcelt lejupielādi</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>Atvērt mapi</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>atkārtot</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Labi</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Jā</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nē</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Atcelt</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Kopēt uz starpliktuvi</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Labi</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Nezināma kļūda</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Iziet</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Iestatījumi</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Par</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>Tiešsaistes palīdzība</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Datne</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Augšupielādē</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Lejupielādē</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>atkārtot</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Servera savienojuma statuss</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>savienots</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>atvienots</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Aizvērt</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Lūdzu, ievadiet paroli</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Nepareiza parole</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Nezināma kļūda</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Labi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Atcelt</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Iestatījumi</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Neviens</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP starpniekserveris</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5 starpniekserveris</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Lejupielādes ātruma limits (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Augšupielādes ātruma limits  (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Pamata</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Uzlabot</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Valoda (nepieciešama pārlāde)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Valoda</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Starpniekservera tips</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Ports:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Lietotājvārds:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Parole: </translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Starpniekserveris prasa paroli</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Tīkls</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Labi</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Atcelt</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Lasīt/Rakstīt</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Tikai lasāms</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Lasīt/Rakstīt</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Tikai lasāms</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Grupa</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Lietotājs</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Atļauja</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Koplietot saiti</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Kopēt uz starpliktuvi</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Labi</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Neuzticams savienojums</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Atcerēties manu izvēli</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Jā</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nē</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Atvērt</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Atvērt datni</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>skatīt &amp;tīmeklī</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>Skatīt datni tīmeklī</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>atkārtot</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Bibliotēka</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Kļūda</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Laiks</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Atinstalēt %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Noņemt konta informāciju...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoga logs</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>teksts</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Jā</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nē</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_nb_NO.ts b/i18n/seafile_nb_NO.ts
new file mode 100644 (file)
index 0000000..f7e665c
--- /dev/null
@@ -0,0 +1,3295 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="nb_NO" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>Mislykkes i å åpne kontoens database</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Innlogging utløpt, logg inn på nytt</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Kontoinnstillinger</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Skriv inn serveradressen</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 er ikke en gyldig serveradresse</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Mislykkes i å lagre kontoinformasjonen</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Mislykkes med å lagre endringene: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Oppdateringen av kontoinformasjonen gikk bra.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Serveradresse</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>E-post</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Avbryt</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Kunne ikke frakoble synkroniseringen av denne kontoen: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>klikk for å åpne websiden</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>pro versjon</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Ingen konto</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Velg</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Konto innstillinger</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Logg inn</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Slette</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Legg til en konto</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>logg ut</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>ikke logget inn</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulær</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Konto</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>epost</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>server</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>prøv på nytt</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Mislyktes i å få aktivitets-informasjon. Vennligst 1%</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Opplasting fulført</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Filen &quot;%1&quot;
+ble lastet opp.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Fil &quot;%1&quot;
+opplasting mislyktes</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Feilet i å generere en avatar folder</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Nedlastings-oppgaver</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>fjern alle gjennomførte oppgaver</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Ingen nedlasting-oppgaver akkurat nå</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Fjern</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Lukk</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Bibliotek</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Sti</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Avslutt denne oppgaven</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>avslutt denne oppgaven</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Fjern denne oppgaven </translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Mislyktes i å avslutte denne oppgaven:
+
+%1 </translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Mislyktes i å fjerne denne oppgaven:
+
+ </translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimalisere</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Lukke</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Bibliotek</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Stjerne merket</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Aktiviteter</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Søk</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>nåværende nedlastings-hastighet</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>nåværende opplastings-hastighet</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Vennligst lukk en folder for å synce</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>ingen server er tilknyttet</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>alle servere tilkoblet</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>noen servere er ikke tilkoblet</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulær</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimalisere</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>lukk</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Velg</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>alternativt slipp en folder for å synkronisere</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>nedlastings-hastighet</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>nedover-pil</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>opplastings-hastighet</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>oppover-pil</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Feil ved oppretting av ccnet konfigurason</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Kan ikke opprette forhåndskonfigurert mappe &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>mislyktes i å lese %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Opprett et bibliotek</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Vennligst velg en mappe</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Oppretter...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Klarte ikke å opprette krypteringsnøkkel for dette biblioteket</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Vennligst velg katalogen som skal synkroniseres</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Mappen %1 finnes ikke</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Skriv inn navnet</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Skriv inn passord</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Passordene stemmer ikke overens</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Ukjent feil</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Kunne ikke legge til nedlastingsoppgave:
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Kunne ikke opprette bibliotek på serveren:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Sti:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Velg</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Navn:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>kryptert</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Passord:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Gjenta passordet:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>status tekst</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Avbryt</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Skriv inn passordet</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Synkroniser biblioteket &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Synkroniser mappe &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Synkroniser til mappe:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>eller</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>synkroniser med en eksisterende mappe</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>opprett en ny synkronisert mappe</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Synkroniser med eksisterende mappe:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Velg en mappe</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>Mappen finnes ikke</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Velg mappen du vil synkronisere</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Din organisasjon tillater ikke å legge et bibliotek utenfor  %1 mappe.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Konflikt med eksisterende fil &quot;%1&quot;. Vennligst velg en annen mappe.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Konflikt med eksisterende bibliotek &quot;%1&quot;, Vennligst velg en annen mappe.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>Mappen &quot;%1&quot; eksisterer allerede. Er du sikker på at du ønsker å synkronisere med den? (innhold vil bli slått sammen)?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Trykk nei for å synkronisere med en annen mappe isteden</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Kan ikke finne et alternativt mappenavn</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Kunne ikke legge til nedlastingsoppgaven:
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Kunne ikke hente nedlastingsinformasjon fra lokalt kodelager:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Nedlastingsbibliotek</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>velg...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Passord for dette biblioteket:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Avbryt</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Endringsinformasjon</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Nye filer</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Slettede filer</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Endrede filer</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Nye mapper</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Slettede mapper</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Åpne</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Cloud filbehandler</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Tilbake</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Fremover</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Hjem</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Last opp filer</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Last opp et bibliotek</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Du har ikke tillatelse til å laste opp filer i dette biblioteket</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Opprett en mappe</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Mappenavn</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Ugyldig mappenavn!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>Navnet &quot;%1&quot; er allerede i bruk.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>prøv på nytt</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Kunne ikke hente filinformasjon&lt;br/&gt;Vennligst %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Skriv navnet på filen å lagre til...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Kunne ikke fjerne filen &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Filen %1 eksisterer allerede.&lt;br/&gt;Ønsker du å overskrive den?&lt;br/&gt;&lt;small&gt;(Velg &quot;nei&quot; for laste opp med et annet navn).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Kunne ikke laste ned filen: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Velg en fil å laste opp</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Velg en mappe å laste opp</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Omdøpe</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Vil du virkelig slette disse elementene</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Kunne ikke opprette mappe</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Velg en fil å oppdatere %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Kunne ikke omdøpe</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Kunne ikke fjerne</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Kunne ikke dele</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Kan ikke lime inn filer fra samme mappe</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Kunne ikke kopiere</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Kunne ikke flytte</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Kunne ikke opprette bibliotek!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Avbryt</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Last opp</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Laster opp %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Last ned</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Laster ned %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 av %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Avbrutt operasjon</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>venter</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Intern serverfeil</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Navn</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Størrelse</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Sist endret</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Lagre som...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Omdøpe</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Slett</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Oppdater</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Kopiere</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Kl&amp;ipp ut</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Lim inn</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Av&amp;bryt nedlasting</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Synkroniser mappen</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Denne funksjonen er bare tilgjengelig i Pro-utgaven
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Kunne ikke opprette mapper</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Kunne ikke opprette midlertidige filer</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Kunne ikke skrive filen til disk</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Kunen ikke fjerne tidligere versjon av den nedlastede filen</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Kunne ikke flytte filen</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 Initialisering</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Vennligst velg en mappe</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Initialisering er ikke fullført. Vil du virkelig avslutte?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Mappen %1 eksisterer ikke</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Velg...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Neste</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Avbryt</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Kontrollerer ditt standard bibliotek...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Oppretter standardbiblioteket...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Kunne ikke opprette standardbiblioteket:
+
+Serverversjonen må være 2.1 eller høyere for å støtte dette.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Kunne ikke hente standard bibliotek:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Kunne ikke opprette standard bibliotek:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Laster ned standard bibliotek...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Kunne ikke laste ned standard bibliotek:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Standardbiblioteket er lastet ned.
+Du kan trykke på &quot;åpne&quot;-knappen for å se på det.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Kunne ikke laste ned standard bibliotek: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Kunne ikke laste ned standard bibliotek:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Hopp over</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Kjør i bakgrunnen</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Åpne</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Avslutte</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Last ned standard bibliotek</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Legg til en konto</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Logg inn pånytt</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Logger inn...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Nettverksfeil:
+ %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Advarsel:&lt;/b&gt; SSL-sertifikatet på denne serveren er ikke bekreftet, fortsett likevel?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Skriv inn serveradressen</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 er en ugyldig serveradresse</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Skriv inn brukernavnet</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Skriv inn datamaskinnavnet</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Kunne ikke lagre nåværende konto</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Skriv inn passordet</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Feil e-postadresse eller passord</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Du har forsøkt å logge inn for ofte. Vennligst vent et minutt.</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Intern serverfeil</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Kunne ikke logge inn: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Kunne ikke logge inn</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Server:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For eksempel: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>eller http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Passord:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>status tekst</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Datamaskinnavn:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>for eksempel Ola&apos;s bærbare</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Logg inn</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Avbryt</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Oppfrisk</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>synkronisert</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indekserer filer</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>synkronisering initialieres</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>laster ned</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>Laster opp</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>synkroniseringen sammenstilles</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>venter på synkronisering</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>serveren er ikke tilkoblet</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>serveren autentiseres</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>automatisk synkronisering er avslått</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>ukjent</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Serveren er fjernet</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Du har ikke logget på serveren</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Du har ikke tillatelse til å åpne dette biblioteket</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Bibliotekets eier har bruk opp all sin tildelte lagringsplass</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Tjenesten er ikke tilgjengelig</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Ingen tilgang til tjenesten</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Interne data er korrupte</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Kunne ikke starte opplastingen</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Kunne ikke starte nedlastingen</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Biblioteket er skadd på serveren</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Konflikt i samordningen</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Serverversjonen er for gammel</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Ukjent feil</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Tildelt lagringsplass er oppbrukt</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Intern serverfeil</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Din %1 klient er for gammel</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Kunne ikke synkronisere dette biblioteket</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Filene er låste av en annen applikasjon</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Biblioteket er slettet på serveren</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Feil oppsto ved forsøk på å åpne den lokale mappen</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>Initialiserer....</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>kobler til server...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indekserer filer...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Oppretter mappe ....</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Slår sammen filendringer...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Utført</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Avbryter</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Avbrutt</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL-feil.</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Nettverksfeil: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Serverfeil</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>kunne ikke åpne sertifikatdatabasen</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 kunne ikke finne en applikasjon til å åpne filen %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Opprettet biblioteket &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Slettet bibliteket &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Omdøpe %1 til</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Kunne ikke laste ned elementet &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>Kunne ikke kopiere</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Lagt til</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Slettet</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Fjernet</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Endret</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Omdøpt</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Flyttet</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Nytt bibliotek</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Fjernet bibliotek</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Omdøpt bibliotek</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Flyttet bibliotek</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>filer</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>mapper</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>og %1 flere</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Tilbakestilte biblioteket til statusen</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Tilbakestilte filen&quot;%1&quot; til statusen %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Gjenopprettet slettet bibliotek</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Endret biblioteksnavn eller beskrivelse</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Akkurat nå</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1 dag siden</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 dager siden</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1 time siden</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 timer siden</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1 minutt siden</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 minutter siden</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Ikke en del av sertifikatet&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Bibliotek &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Dette biblioteket er ikke lastet ned enda</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Feil: </translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Kodelagerikon</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>Kodelagernavn</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Tekstetikett</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Eier:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Sist endret:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>endringstid</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Størrelse:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Lokal sti:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Status:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Kodelagerstatus</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Navn:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Lukke</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Dette biblioteket har ikke blitt lastet ned</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Nylig oppdatert</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Mine biblioteker</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Underbiblioteker</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Synkroniserte biblioteker</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Slå av automatisk synkronisering</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Slå på automatisk synkronisering</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Vis &amp;detaljer</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Vis bibliotekets detaljer</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Synkroniser dette biblioteket</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Synkroniser dette biblioteket</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Nylig oppdatert</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Synkroniser &amp;nå</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Synkroniser dette biblioteket umiddelbart</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Avbryt nedlasting</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Avbryt nedlastingen av dette biblioteket</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Åpne mappe</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>åpne lokal mappe</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;frakoble synkronisering</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>Frakoble synkroniseringen av dette biblioteket</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Se i nettskyen</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>se dette biblioteket på seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Åpne Cloud filbehandleren</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>åpne dette biblioteket i den innebygde Cloud filbehandleren</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Synkroniser dette biblioteket pånytt</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>frakoble og synkroniser dette biblioteket pånytt</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Kunne ikke frakoble synkroniseringen av bibliotek &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Kunne ikke avbryte denne oppgaven:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Nedlastingen har blitt avbrutt</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Kunne ikke slette filen &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Kunne ikke laste opp filen: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>prøv på nytt</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Kunne ikke hente biblioteksinformasjonen&lt;br/&gt;Vennligst %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Advarsel:&lt;/b&gt; SSL-sertifikatet på denne serveren er ikke bekreftet, fortsett likevel?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Kunne ikke initialisere loggen: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Ukjent feil</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Slå av automatisk synkronisering</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Slå på automatisk synkronisering</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Avslutt</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Vis hovedvindu</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Innstillinger</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Åpne &amp;loggmappen</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Om</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Vis applikasjonens &quot;om&quot; boks</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Hjelp på nett</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Fil</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>automatisk synkronisering er avslått</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Laster opp</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Laster ned</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>noen servere er ikke tilkoblet</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Servernes tilkoblingsstatus</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>tilkoblet</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>frakoblet</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Lukke</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Skriv inn bibliotekspassord</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Skriv inn passordet for bibliotek %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Skriv inn passordet</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Feil passord</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Ukjent feil</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Avbryt</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Innstillinger</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Ingen</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP mellomtjener</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5 mellomtjener</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Du har skiftet språk. Start om for å bruke det?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Skjul hovedvinduet ved oppstart</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Gi melding når bibliotekene er synkroniserte</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Aktiver synkronisering av midlertidige filer for MS Office/ LibreOffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Hastighetsbegrensing (KB/s) for nedlasting:</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Hastighetsbegrensning (KB/s) for opplasting: </translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Grunnleggende</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Ikke frakoble synkronisering av et bibliotek automatisk</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Ikke frakoble synkroniseringen av et bibliotek automatisk når dens lokale mappe er fjernet eller utilgjengelig av andre årsaker.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Ikke frakoble synkroniseringen av et bibliotek når det ikke kan gjenfinnes på serveren</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Ikke frakoble synkronseringen av et bibliotek automatisk når det ikke gjenfinnes på serveren</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Slå på FinderSync-utvidelsen</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Slå på Windows utforsker utvidelsen</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Ikke verifiser serversertifikatet med HTTPS-sykronisering</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Avansert</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Språk (krever omstart)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Språk</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Mellomtjenertype:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Vert:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Port:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Brukernavn:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Passord:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Mellomtjeneren krever et passord</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Nettverk</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Avbryt</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Delingslenke</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Delingslenke:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Kopier til utklippstavlen</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Ubekreftet tilkobling</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 bruker et et ugyldig sikkerhetssertifikat. Tilkoblingen kan være usikker. Ønsker du å fortsette?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Nåværende RSA-nøkkel fingeravtrykk er %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Tidligere RSA-nøkkel fingeravtrykk er %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Husk valget mitt</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nei</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Åpne</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Åpne denne filen</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>Se på &amp;Web</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>se denne filen på websiden</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>prøv på nytt</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Kunne ikke hente informasjon for favorittmarkerte filer&lt;br/&gt;Vennligst %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Du har ingen favorittmarkerte filer enda.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Avinstallere %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Ønsker du å fjerne %1 kontoinformasjonen?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Fjerner kontoinformasjon...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>tekst</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nei</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_nl_BE.ts b/i18n/seafile_nl_BE.ts
new file mode 100644 (file)
index 0000000..3230089
--- /dev/null
@@ -0,0 +1,3292 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="nl_BE" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>mislukt om de database account te openen</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Account instellingen</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Gelieve het server adres in te vullen</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 is geen geldig server adres</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Mislukt om de account informatie op te slaan</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Mislukt om aanpassingen op te slaan: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Huidige account informatie succesvol geüpdatet</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Server adres</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Email</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleer</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Mislukt om het synchroniseren van deze account te stoppen: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>klik om de website te openen</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Geen account</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Account instellingen</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Voeg een account toe</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulier</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Account</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>email</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>server</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>probeer opnieuw</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Mislukt om de activiteiten informatie te krijgen. Gelieve%1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Mislukt om de avatars map te maken</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Download taken</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>verwijder alle succesvolle taken</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Momenteel geen download taken.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Wissen</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Sluiten</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Bibliotheek</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Pad</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Annuleer deze taak</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>annuleer deze taak</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Verwijder deze taak</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Mislukt om deze taak te annuleren:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Mislukt om deze taak te verwijderen:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimaliseren</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Sluiten</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Bibliotheken</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Favoriet</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Activiteiten</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>huidige downloadsnelheid</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>huidige uploadsnelheid</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Gelieve een te synchroniseren map te kiezen</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>geen server verbonden</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>alle servers verbonden</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>enkele servers zijn niet verbonden</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulier</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimaliseren</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>sluiten</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Selecteer</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>of Plaats Map om te Synchroniseren</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>downloadsnelheid</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>pijlomlaag</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>uploadsnelheid</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>pijlomhoog</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Fout tijdens het aanmaken van ccnet configuratie</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>mislukt om %1 te lezen</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Aanmaken bibliotheek</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Gelieve een map te kiezen</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Aanmaken...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Gelieve de te synchroniseren map te kiezen</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>De map %1 bestaat niet</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Gelieve de naam in te vullen</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Gelieve het paswoord in te vullen</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Paswoorden komen niet overeen</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Onbekende fout</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Mislukt om download taak toe te voegen:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Mislukt om een bibliotheek aan te maken op de server:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Pad:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Kies</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Naam:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>versleuteld</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Paswoord:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Nogmaals Paswoord:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>status tekst</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleer</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Gelieve het paswoord in te vullen</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Synchronisatie bibliotheek &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Mislukt om download taak toe te voegen:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Mislukt om de repo download informatie te halen:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Download Bibliotheek</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>kies...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Paswoord voor deze bibliotheek:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleer</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Aanpassingen Details</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Cloud Bestand Browser</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Terug</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Verder</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Startpagina</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Bestanden uploaden</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Een map uploaden</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Je hebt geen toelating om bestanden naar deze bibliotheek te uploaden</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Maak een map</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Map naam</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Ongeldige map naam!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>De naam &quot;%1&quot; is reeds in gebruik.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>probeer opnieuw</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Mislukt om bestand informatie te krijgen&lt;br /&gt;Gelieve %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Bestand %1 bestaat reeds.&lt;br/&gt;Wil je dit overschrijven?&lt;br/&gt;&lt;small&gt;(Kies Nee om te uploaden onder een andere naam).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Mislukt om bestand te downloaden: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Kies een bestand om te uploaden</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Kies een map om te uploaden</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Hernoemen</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Ben je zeker dat je deze items wilt verwijderen</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Aanmaken map is mislukt</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Kies een bestand om te updaten %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Hernoemen is mislukt</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Verwijderen is mislukt</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Delen is mislukt</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Kan geen bestanden uit dezelfde map plakken</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Kopiëren is mislukt</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Verplaatsen is mislukt</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleer</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Uploaden</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Uploaden %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Download</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Downloaden %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 van %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Handeling geannuleerd</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>in behandeling</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Interne Server Fout</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Naam</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Grootte</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Laatste Aanpassing</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Hernoem</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Verwijder</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Update</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Kopieer</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>S&amp;nij</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Plak</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Mislukt om mappen te maken</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Mislukt op tijdelijke bestanden te maken</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Mislukt om bestand naar de schijf te schrijven</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Mislukt om de oude versie van het gedownloade bestand te verwijderen</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Mislukt om bestand te verplaatsen</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 Initialisatie</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Gelieve een map te kiezen</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Initialisatie is nog niet gedaan. Zeker dat u wil stoppen?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>De map %1 bestaat niet</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Kies...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Volgende</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleer</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Controleer je standaard bibliotheek...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Aanmaken standaard bibliotheek...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Mislukt om de standaard bibliotheek aan te maken:
+
+De server versie moet minstens 2.1 of hoger zijn om dit te ondersteunen.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Mislukt om de standaard bibliotheek te halen:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Mislukt om de standaard bibliotheek aan te maken:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Downloaden standaard bibliotheek...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Mislukt om de standaard bibliotheek te downloaden:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>De standaard bibliotheek werd gedownload.
+Je kan op &quot;Open&quot; klikken om het te bekijken.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Fout tijdens het downloaden van de standaard bibliotheek: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Mislukt op de standaard bibliotheek te downloaden:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Overslaan</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Draaien in Achtergrond</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Open</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Klaar</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Download Standaard Bibliotheek</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Voeg een account toe</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Inloggen...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Netwerk Fout:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Waarschuwing:&lt;/b&gt; Het ssl certificaat van deze server is niet betrouwbaar, toch doorgaan?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Gelieve het server adres in te vullen</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 is geen geldig server adres</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Gelieve de gebruikersnaam in te vullen</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Vul de computernaam in</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Mislukt om de huidige account op te slaan</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Gelieve het paswoord in te vullen</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Foute email of paswoord</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Te snel ingelogd, wacht een minuutje</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Interne Server Fout</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Mislukt om in te loggen: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Mislukt om in te loggen</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Server:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Bijvoorbeeld: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>of http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Paswoord:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>status tekst</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Computernaam:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>v.b. Jim&apos;s laptop</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Login</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleer</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Vernieuwen</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>gesynchroniseerd</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indexeren bestanden</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>initialisatie synchronisatie</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>bezig met downloaden</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>bezig met uploaden</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>synchronisatie samenvoeging</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>wachten ome te synchroniseren</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>server niet verbonden</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>server authenticatie</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>auto synchronisatie is uitgeschakeld</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>onbekend</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Server werd verwijderd</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Je bent niet ingelogd op de server</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Je hebt geen toelating voor toegang tot deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>De opslagruimte van eigenaar van de bibliotheek is opgebruikt</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Remote service is niet beschikbaar</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Toegang geweigerd tot de service</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Interne gegevens beschadigd</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Mislukt op de upload te starten</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Mislukt om de download te starten</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Bibliotheek is beschadigd op de server</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Conflict in samenvoeging</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Server versie is te oud</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Onbekende fout</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>De opslag quota is opgebruikt</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Interne server fout</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Je %1 client is te oud</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Mislukt om deze bibliotheek te synchroniseren</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Bestanden werden geblokkeerd door andere toepassing</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Bibliotheek werd verwijderd op de server</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Fout bij openen lokale map</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>initialisatie...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>verbinden met server...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indexatie bestanden...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Aanmaken map...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Samenvoegen aanpassingen bestand...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Klaar</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Annulatie</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Geannuleerd</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL Fout</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Netwerk Fout: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Server Fout</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>mislukt om de certs databank te openen</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 kon geen toepassing vinden om het bestand %2 te openen</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Aanmaken bibliotheek &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Bbibliotheek &quot;%1&quot; verwijderd</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Hernoem %1 naar</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Kan item &quot;%1&quot; niet downloaden</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>kopiëren is mislukt</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Toegevoegd</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Verwijderd</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Verwijderd</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Aangepast</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Hernoemd</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Verplaatst</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Map toegevoegd</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Map verwijderd</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Map hernoemd</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Map verplaatst</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>bestanden</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>mappen</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>en %1 meer</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Bibliotheek teruggezet naar status van</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Bestand &quot;%1&quot; teruggezet naar status van %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Terugplaatsen verwijderde map</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Bibliotheek naam of beschrijving aangepast</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Nu</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1 dag geleden</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 dagen geleden</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1 uur geleden</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 uren geleden</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1 minuut geleden</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 minuten geleden</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Geen Deel van Certificaat&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Bbiliotheek &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Deze bibliotheek werd nog niet gedownload</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Fout:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>RepoIcon</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>RepoName</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>TextLabel</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Eigenaar:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Laatst Aangepast:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Grootte:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Lokaal Pad:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Status:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>RepoStatus</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Naam:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Sluiten</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Deze bibliotheek werd niet gedownload</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Recentelijk Aangepast</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Mijn Bibliotheken</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Onderverdeling Bibiliotheken</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Gesynchroniseerde Bibliotheken</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Uitschakelen auto sync</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Inschakelen auto sync</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Toon de details van deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Synchroniseer deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Synchroniseer deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Recentelijk Aangepast</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Synchroniseer deze bibliotheek onmiddellijk</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Cancel download</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Annulatie download van deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Open map</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>open lokale map</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Unsync</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>annulatie synchronisatie van deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Bekijk in de cloud</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>Bekijk deze bibliotheek op seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Hersynchroniseer deze bibliotheek opnieuw</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>annulatie synchronisatie en hersynchronisatie van deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Mislukt om synchronisatie van bibliotheek &quot;%1&quot; te annuleren</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Mislukt om deze taak te annuleren:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>De download werd geannuleerd</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Kan bestand &quot;%1&quot; niet verwijderen</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Mislukt om bestand te uploaden: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>probeer opnieuw</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Mislukt om bestand informatie te krijgen&lt;br /&gt;Gelieve %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Waarschuwing:&lt;/b&gt; Het ssl certificaat van deze server is niet betrouwbaar, toch doorgaan?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Mislukt om de log te initialiseren: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Onbekende fout</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Uitschakelen auto sync</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Inschakelen auto synchronisatie</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Afsluiten</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Toon hoofdvenster</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Instellingen</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>&amp;Log map openen</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Hierover</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Toon de toepassings&apos; Hierover kader</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Online help</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Bestand</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>auto synchronisatie is uitgeschakeld</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Uploaden</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Downloaden</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>enkele servers zijn niet verbonden</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Servers verbindingsstatus</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>verbonden</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>verbinding verbroken</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Sluiten</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Geef het bibliotheek paswoord</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Geef het paswoord voor bibliotheek %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Vul het paswoord in</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Onjuist paswoord</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Onbekende fout</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleer</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Instellingen</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Je hebt de taal veranderd. Herstarten om dit toe te passen?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Verberg hoofdvenster na start</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Melden wanneer bibliotheken gesynchroniseerd zijn</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Activeren synchronisatie van tijdelijke bestanden MSOffice/Libreoffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Download snelheid limiet (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Upload snelheid limiet (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Basis</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Annuleer niet automatisch het synchroniseren van een bibliotheek</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Annuleer niet automatisch het synchroniseren van een bibliotheek als de lokale map verwijderd is of om andere redenen niet toegankelijk is.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Annuleer het synchroniseren van een bibliotheek niet wanneer deze niet gevonden wordt op een server</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Annuleer niet automatisch het synchroniseren van een bibliotheek wanneer deze niet gevondenn wordt op een server</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Controleer het server certificaat in HTTPS synchronisatie niet</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Geavanceerd</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Taal (herstart vereist)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Taal</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>0</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Paswoord:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleer</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Deel Link</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Deel link:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Kopieer naar klembord</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Onvertrouwde Verbinding</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 gebruikt een ongeldig veiligheidscertificaat. De verbinding kan onveilig zijn. Wil je verdergaan?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Huidige RSA sleutel vingerafdruk is %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Vorige RSA sleutel vingerafdruk is %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Onthou mijn keuze</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nee</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Open</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Open dit bestand</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>bekijk op &amp;Web</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>bekijk dit bestand op de website</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>probeer opnieuw</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Mislukt om informatie van favoriete bestanden te bekijken&lt;br/&gt;Gelieve %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Je hebt nog geen favoriete bestanden.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Desinstalleer %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Wil je de %1 account info verwijderen?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Verwijdering account info...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>tekst</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nee</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_nl_NL.ts b/i18n/seafile_nl_NL.ts
new file mode 100644 (file)
index 0000000..248b321
--- /dev/null
@@ -0,0 +1,3295 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="nl_NL" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>Over %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; REV %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>Over</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Controleren op updates</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>kon accountdatabase niet openen</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Autorisatie verlopen, graag opnieuw aanmelden</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Accountinstellingen</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Geef serveradres op</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 is geen geldig serveradres</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Kon accountinformatie niet opslaan</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Kon de wijzigingen niet opslaan: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Bijwerken huidige accountinformatie gelukt</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoogvenster</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Serveradres</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>E-mail</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Kon bibliotheken van dit account niet desynchroniseren: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>klik om de website te openen</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>pro-versie</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Geen account</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Kies</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Accountinstellingen</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Aanmelden</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Verwijderen</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Account toevoegen</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Afmelden</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>niet aangemeld</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulier</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Account</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>e-mail</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>server</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Bestandsactiviteit wordt uitsluitend ondersteund in %1 Server Professional editie.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>opnieuw</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Ophalen van informatie activiteiten mislukt. %1 a.u.b.</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Upload gelukt</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Bestand &quot;%1&quot;
+succesvol geüpload.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Bestand &quot;%1&quot;
+kon niet worden geüpload.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Machtigingen Fout!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorisatie verlopen</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Bestand bestaat niet</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Upload Fout: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Kon de avatarsmap niet aanmaken</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Machtigingen Controleren</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Taken downloaden</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>verwijder alle succesvolle taken</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Op dit moment geen downloadtaken</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Opschonen</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Sluiten</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Bibliotheek</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Pad</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Deze taak annuleren</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>deze taak annuleren</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Deze taak verwijderen</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Kon deze taak niet annuleren:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Kon deze taak niet verwijderen:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimaliseren</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Sluiten</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Bibliotheken</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Favorieten</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Activiteiten</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Zoeken</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>huidige downloadsnelheid</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>huidige uploadsnelheid</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Kies een map om te synchroniseren</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>geen server verbonden</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>alle servers verbonden</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>sommige servers niet verbonden</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulier</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimaliseren</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>sluiten</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Selecteer</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>brand</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>of sleep een map om te synchroniseren</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>downloadsnelheid</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>pijlomlaag</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>uploadsnelheid</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>pijlomhoog</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Fout bij het maken van de ccnet-configuratie</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Kon de voorgeconfigureerde map &quot;%1&quot; niet aanmaken</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>kon %1 niet lezen</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Een bibliotheek aanmaken</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Kies een map</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Aanmaken...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Kon geen encryptiesleutel voor deze bibliotheek genereren</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Kies een map om te synchroniseren</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>De map %1 bestaat niet</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Geef de naam op</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Geef het wachtwoord op</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Wachtwoorden komen niet overeen</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Onbekende fout</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Kon geen downloadtaak toevoegen:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Kon geen bibliotheek op de server aanmaken:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Pad:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Kies</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Naam:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>gecodeerd</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Wachtwoord:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Wachtwoord opnieuw:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>statustekst</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>Initialiseren van %1 client mislukt</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>%1 onverwacht afgesloten</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Geef het wachtwoord op</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Synchroniseer bibliotheek &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Synchroniseer map &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Synchroniseer naar map:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>of</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>synchroniseer met een bestaande map</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>een nieuwe synchronisatiemap aanmaken</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Synchroniseer met deze bestaande map:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Kies een map</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>De map bestaat niet</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Kies de map om te synchroniseren.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Je organisatie heeft de mogelijkheid een bibliotheek buiten de map %1 te plaatsen uitgeschakeld.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflicteert met bestaande bestand &quot;%1&quot;. Kies een andere map.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflicteert met bestaande bibliotheek &quot;%1&quot;. Kies een andere map.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>De map &quot;%1&quot; bestaat reeds. Weet je zeker dat je hiermee wilt synchroniseren (inhoud zal worden samengevoegd)?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Kies nee om in plaats daarvan met een nieuwe map te synchroniseren</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Kan geen alternatieve mapnaam vinden</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Kon geen downloadtaak toevoegen:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Kon de repository download informatie: %1 niet ophalen</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Bibliotheek downloaden</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>kies...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Wachtwoord voor deze bibliotheek:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Wijzigingendetails</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Toegevoegde bestanden</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Verwijderde bestanden</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Gewijzigde bestanden</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Toegevoegde mappen</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Verwijderde mappen</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Open</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Bovenliggende map openen</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Bestandsbeheer cloud</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Terug</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Vooruit</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Begin</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Bestanden uploaden</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Een map uploaden</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Je hebt geen rechten op bestanden naar deze bibliotheek te uploaden</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Een map aanmaken</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Vernieuwen</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Mapnaam</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Ongeldige mapnaam!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>De naam &quot;%1&quot; is al in gebruik.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>opnieuw</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Kon geen bestandsinformatie ophalen&lt;br/&gt;%1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>Deze map is leeg.</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Geef de bestandsnaam op...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Kon het bestand &quot;%1&quot; niet verwijderen</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Geef het pad naar de map waarheen je wilt opslaan op...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Wil je het bestaande bestand &quot;%1&quot; overschrijven?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>Bestand &quot;%1&quot; is niet gesynchroniseerd</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Bestand %1 bestaat reeds.&lt;br/&gt;Wil je deze overschrijven?&lt;br/&gt;&lt;small&gt;(Kies nee om te uploaden met een alternatieve naam)&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Bestand bestaat niet</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Kon bestand niet downloaden: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Kies een te uploaden bestand</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Kies een te uploaden map</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Hernoemen</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Weet je zeker dat je deze items wilt verwijderen?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Aanmaken map mislukt</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Bestandsvergrendeling mislukt</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Kies een bestand om bij te werken %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Hernoeming mislukt</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Verwijderen mislukt</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Delen mislukt</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Kan geen bestanden plakken vanuit dezelfde map</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>Kan de map niet plakken in zijn onderliggende map</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Kopiëren mislukt</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Verplaatsen mislukt</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Aanmaken bibliotheek mislukt!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Je hebt geen rechten om naar deze map te uploaden</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorisatie verlopen</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Machtigingen Fout!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Bibliotheek/Map niet gevonden.</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Zoek bestanden</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Uploaden</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Uploaden %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Downloaden</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Downloaden %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 van %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>Opnieuw</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Overslaan</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Afbreken</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>Opslaan</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>Bestand opslaan niet gelukt</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Naam</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Grootte</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Laatst aangepast</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Laat zien in map</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Laat zien in map</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Bewerking geannuleerd</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>in behandeling</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>Opdracht afgebroken</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Interne serverfout</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>De opslaglimiet is bereikt</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>vergrendeld door %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Naam</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Grootte</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Laatst gewijzigd</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>Op&amp;slaan als...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Vergrendelen</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Hernoemen</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Verwijderen</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Delen met groep</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Bijwerken</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Kopiëren</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Knippen</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Plakken</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Download &amp;annuleren</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Synchroniseer deze map</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Deze eigenschap is alleen beschikbaar in de pro-versie
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>%1 downloadlink &amp;genereren</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Delen met gebruiker</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>Interne %1link g&amp;enereren</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>Op&amp;slaan als...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>&amp;Ontgrendelen</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Kon alleen-lezen bestanden niet verwijderen</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Kon alleen-lezen bestanden niet knippen</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>Opnieuw Uploaden</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>Lokale versie verwijderen</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>Lokale versie opslaan als...</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Kon geen mappen aanmaken</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Kon geen tijdelijke bestanden aanmaken</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Kon bestand niet naar schijf wegschrijven</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Kon oudere versie van het gedownloade bestand niet verwijderen</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Kon bestand niet verplaatsen</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 initialisatie</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Kies %1-map</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Kies een map</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Initialisatie is niet afgerond. Wil je echt afsluiten?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>De map %1 bestaat niet</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Kies een map</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Kies een map. We zullen hierin een submap %1 aanmaken. Wanneer je een bibliotheek download zal deze hier standaard worden opgeslagen.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Kies...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Volgende</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Controleren van je standaardbibliotheek...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Aanmaken van de standaardbibliotheek...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Kon geen standaardbibliotheek aanmaken:
+
+Deze functie wordt alleen ondersteund in serverversie 2.1 of hoger.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Kon de standaardbibliotheek niet ophalen:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Kon de standaardbibliotheek niet aanmaken:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Standaardbibliotheek downloaden...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Kon standaardbibliotheek niet downloaden:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>De standaardbibliotheek is gedownload.
+Je kunt op de knop &quot;Openen&quot; klikken om deze te bekijken.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Fout bij het downloaden van de standaardbibliotheek: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Kon standaardbibliotheek niet downloaden:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Overslaan</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Op de achtergrond uitvoeren</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Open</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Afronden</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Standaardbibliotheek downloaden</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>Meer laden</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>Upload log bestanden mislukt</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Upload log bestanden</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>Comprimeren</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 van de %2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Een account toevoegen</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Opnieuw aanmelden</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Aanmelden...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Netwerkfout:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Waarschuwing:&lt;/b&gt; Het SSL-certificaat van deze server is niet vertrouwd. Toch doorgaan?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Geef serveradres op</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 is geen geldig serveradres</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Geef de gebruikersnaam op</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Geef de computernaam op</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Kon huidige account niet opslaan</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1 serveradres</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>Server adres kan niet leeg zijn</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1 is geen valide server adres. Het moet starten met &apos;https://&apos;</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Geef het wachtwoord op</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>E-mailadres of wachtwoord onjuist</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Te kort na elkaar aangemeld. Een minuut wachten alstublieft</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Interne serverfout</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Kon niet aanmelden: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Kon niet aanmelden</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Server:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Bijvoorbeeld: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>of http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Wachtwoord:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>statustekst</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Computernaam</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>E-mailadres / Gebruikersnaam:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>bijv. Laptop van Jan</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Aanmelden</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Automatisch Inloggen</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Je bent afgemeld.</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>aanmelden</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Een account toevoegen</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Vernieuwen</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation>&quot;%1&quot;is gesynchroniseerd</translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation>Bestanden geupload naar &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation>Bestand %1 conflict</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Deel %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Geef de groepsnaam op</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Voer gebruikersnaam of email adres in</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Succesvol bijgewerkt</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>Actie om te delen mislukt: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Succesvol verwijderd</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Kon deelinformatie van de map niet ophalen</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Kon je groeps- en contactinformatie niet ophalen</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Geef de gebruikersnaam op</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Geef de groepsnaam op</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>Groep &quot;%1&quot; bestaat niet</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Reeds gedeeld met groep %1</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Reeds gedeeld met gebruiker %1</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>De vorige opdracht wordt nog uitgevoerd</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoogvenster</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Delen met:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Delen</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Rechten:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Lezen en schrijven</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Alleen lezen</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Sluiten</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>gesynchroniseerd</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>bestanden indexeren</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>synchronisatie initialiseren</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>downloaden</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>uploaden</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>Synchronisatie samenvoegen</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>wachten op synchronisatie</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>server niet verbonden</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>serverauthenticatie</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>automatische synchronisatie is uitgeschakeld</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>onbekend</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Server is verwijderd</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Je bent niet op de server aangemeld</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Je hebt geen toegangsrechten tot deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>De opslaglimiet van de bibliotheekeigenaar is bereikt</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Dienst op afstand is niet beschikbaar</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Toegang tot dienst geweigerd</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Interne data bechadigd</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Kon upload niet starten</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Kon download niet starten</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Bibliotheek is beschadigd op de server</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Conflict bij het samenvoegen</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Serverversie is te oud</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Onbekende fout</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Netwerkfout</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>Kan het server adres niet vinden</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>Kan geen verbinding maken met de server</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>Kan geen veilige verbinding opzetten. Controleer het SSL certificaat van de server.</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Serverfout</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Ongeldig verzoek</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>Niet genoeg geheugen</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>Bibliotheek is op de server verwijderd</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>Bibliotheek is beschadigd op de server</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>De opslaglimiet is bereikt</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Interne serverfout</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Je applicatie %1 is te oud</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Kon deze bibliotheek niet synchroniseren</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Bestanden zijn door een andere applicatie vergrendeld</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Bibliotheek is op de server verwijderd</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Er is een fout opgetreden bij het aanroepen van de lokale map</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>Initialiseren...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>Kon lokale bestanden niet indexeren</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>Kon geen lokale bestanden aanmaken</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>Kon geen lokale bestandswijzigingen samenvoegen</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Wachtwoord onjuist. Download opnieuw</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Interne fout</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>verbinding maken met server...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>bestanden indexeren...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Bestandslijst downloaden...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Bestanden downloaden...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Map aanmaken...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Bestandswijzigingen samenvoegen...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Klaar</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>serverinfo controleren...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Annuleren</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Geannuleerd</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL-fout</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Netwerkfout: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Serverfout</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>kon certificatendatabase niet openen</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>Bestand &quot;%1&quot; bestaat niet in &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 kon geen applicatie vonden op het bestand %2 te openen</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Bibliotheek &quot;%1&quot; aangemaakt</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Bibliotheek &quot;%1&quot; verwijderd</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>%1 hernoemen naar</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Kon item &quot;%1&quot; niet downloaden</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>kopie mislukt</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Toegevoegd</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Verwijderd</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Verwijderd</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Gewijzigd</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Hernoemd</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Toegevoegd of gewijzigd</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Verplaatst</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Map toegevoegd</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Map verwijderd</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Map hernoemd</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Map verplaatst</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>bestanden</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>mappen</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>en nog %1 andere</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Bibliotheek teruggezet naar de status van</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Bestand &quot;%1&quot; teruggezet naar de status van %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Verwijderde map hersteld</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Naam of beschrijving van de bibliotheek gewijzigd</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>Automatisch samenvoegen door het %1systeem</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Zojuist</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1 dag geleden</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 dagen geleden</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1 uur geleden</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 uur geleden</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1 minuut geleden</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 minuten geleden</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Geen onderdeel van certificaat&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Synchroniseer deze bibliotheek naar:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Synchroniseer deze map naar:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Map</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Alleen-lezen map</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Document</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF-document</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Afbeeldingsbestand</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Tekstdocument</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Audiobestand</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Videobestand</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Worddocument</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>PowerPoint-document</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Exceldocument</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>Het pad &quot;%1&quot; conflicteert met het systeempad</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>Het pad &quot;%1&quot; conflicteert met een bestaande bibliotheek</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>uploaden van de bestandslijst</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>Pad is ongeldig</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Fout bij indexeren</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation>Fout tijdens het uploaden</translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation>Fout tijdens het downloaden</translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>Bestand bestaat niet</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Bibliotheek &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Deze bibliotheek is nog niet gedownload</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Fout:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>elke %1 seconden</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Bibliotheeksymbool</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>Bibliotheeknaam</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Tekstlabel</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Eigenaar:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Laatst gewijzigd:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Grootte:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Lokaal pad:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Status:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Bibliotheekstatus</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Naam:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Synchronisatie-interval:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Sluiten</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Deze bibliotheek is niet gedownload</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>Kon het bestand &quot;%1&quot; van de niet-bestaande bibliotheek &quot;%2&quot; niet openen</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Onlangs bijgewerkt</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Mijn bibliotheken</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Subbibliotheken</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Gedeeld met mij</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Gedeeld met iedereen</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Gedeeld met groepen</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Gesynchroniseerde bibliotheken</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>Synchronisatie initialiseren</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Automatische synchronisatie uitschakelen</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Automatische synchronisatie inschakelen</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>&amp;Details weergeven</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Details van deze bibliotheek weergeven</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Synchroniseer deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Synchroniseer deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Onlangs bijgewerkt</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>&amp;Nu synchroniseren</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Synchroniseer deze bibliotheek meteen</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>Download &amp;annuleren</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Download van deze bibliotheek annuleren</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>Map &amp;openen</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>lokale map openen</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>Lokale map &amp;openen</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Desynchroniseren</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>desynchroniseer deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>In cloud weergeven</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>Geef deze bibliotheek in de cloud weer</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Delen met gebruiker</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Deel deze bibliotheek met een gebruiker</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Delen met groep</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Deel deze bibliotheek met een groep</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Open bestandsbeheer cloud</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>Open deze bibliotheek in de ingebouwde cloud-bestandsbeheerder</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Hersynchroniseer deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>de- en hersynchroniseer deze bibliotheek</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Synchronisatie-interval instellen</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Kon de bibliotheek &quot;%1&quot; niet desynchroniseren</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Kon deze taak niet annuleren:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>De download is geannuleerd</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>Kon het bestand &quot;%1&quot; niet met zichzelf overschrijven</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Kon het bestand &quot;%1&quot; niet verwijderen</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Kon bestand niet uploaden: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Synchronisatie-interval (in seconden):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Synchronisatieinterval voor bibliotheek &quot;%1&quot; instellen</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>Bibliotheken zoeken</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>opnieuw</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Kon geen informatie over bibliotheken ophalen&lt;br/&gt;%1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Waarschuwing&lt;/b&gt; Het SSL-certificaat van deze server is niet vertrouwd. Toch doorgaan?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>Kon standaardaccount niet toevoegen</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Kon logbestand niet initialiseren: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nee</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>Interne %1-link</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Kopiëren naar klembord</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Onbekende fout</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Automatische synchronisatie uitschakelen</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Automatische synchronisatie inschakelen</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Afsluiten</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Toon applicatiescherm</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Instellingen</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>&amp;Map %1 openen</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>Map %1 openen</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Map &amp;logboeken openen</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>Synchronisatie fouten laten zien.</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Over</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Toon het scherm met informatie over de applicatie</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Online help</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Bestand</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>automatische synchronisatie is uitgeschakeld</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Uploaden</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Downloaden</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>map %1 logboeken openen</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>open %1 online hulp</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>sommige servers niet verbonden</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Upload log bestanden</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>upload %1 log bestanden</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>Eerst inloggen A.U.B.</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>In map &amp;tonen</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>In map tonen</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>Bestanden zoeken</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>opnieuw</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Kon niet zoeken&lt;br/&gt;
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Verbindingsstatus servers</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>verbonden</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>niet verbonden</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Sluiten</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Geef het bibliotheekwachtwoord op</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Geef het wachtwoord voor de bibliotheek %1 op</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Geef het wachtwoord op</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Wachtwoord onjuist</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Onbekende fout</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Instellingen</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>%1 automatisch opstarten na het aanmelden</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>%1-icoon verbergen</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Geen</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP-proxy</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5-proxy</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Systeem proxy</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Je hebt de taal gewijzigd. Herstarten op de wijziging door te voeren?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>Het proxy server adres kan niet leeg zijn</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>De proxy netwerkpoort is onjuist</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>De proxy gebruikersnaam mag niet leeg zijn</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>Het proxy wachtwoord mag niet leeg zijn</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Applicatiescherm verbergen na opstarten</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Melding wanneer bibliotheken zijn gesynchroniseerd</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Synchronisatie tijdelijke bestanden van MSOffice/Libreoffice inschakelen</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Snelheidslimiet download (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Snelheidslimiet upload (KB/s)</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Basis</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Bibliotheek niet automatisch desynchroniseren</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Bibliotheek niet automatisch desynchroniseren wanneer de lokale map is verwijderd of niet toegankelijk is om andere redenen.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Niet desynchroniseren wanneer niet op de server gevonden</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Bibliotheek niet automatisch desynchroniseren wanneer deze niet op de server kan worden gevonden</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>FinderSync-extensie inschakelen</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Verkenner-extensie inschakelen</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>Automatisch op updates controleren</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Het servercertificaat bij HTTPS-synchronisatie niet verifiëren</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Synchroniseren met een bestaande map met een andere naam inschakelen</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Geavanceerd</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Taal (herstart noodzakelijk)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Taal</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Proxytype:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Host:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Poort:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Gebruikersnaam:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Wachtwoord:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Proxyserver vereist een wachtwoord</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Netwerk</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Lezen en schrijven</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Alleen lezen</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Verwijder gedeelde onderdeel</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>Klik om aan te passen</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Aangemaakt door %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Lezen en schrijven</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Alleen lezen</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Groep</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Gebruiker</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Rechten</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>De vorige opdracht wordt nog uitgevoerd</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Deellink</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Deellink:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Directe download</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Kopiëren naar klembord</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Niet-vertrouwde verbinding</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 gebruikt een ongeldig beveiligingscertificaat. De verbinding kan onveilig zijn. Wil je toch doorgaan?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Huidige RSA-vingerafdruk is %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Voorgaande RSA-vingerafdruk is %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Mijn keuze onthouden</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nee</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Open</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Open dit bestand</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>op web weergeven</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>bekijk dit bestand op de website</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>opnieuw</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Kon geen informatie over favorieten ophalen&lt;br/&gt;%1 a.u.b.</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Je hebt nog geen favoriete bestanden.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Bestands synchronisatie fouten</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>Geen synchronisatie fouten.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Dubbel klik om de bibliotheek te openen.</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Bibliotheek</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Pad</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Fout</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Tijd</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mText</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>Dit apparaat onthouden</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuleren</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Ok</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Deïnstalleer %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Wil je de accountinformatie van %1 verwijderen?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Accountinformatie verwijderen...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>tekst</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nee</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_pl_PL.ts b/i18n/seafile_pl_PL.ts
new file mode 100644 (file)
index 0000000..b653faf
--- /dev/null
@@ -0,0 +1,3306 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="pl_PL" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>O %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 Klient %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; Rew. %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>O programie</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Sprawdź aktualizacje</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>nie udało się otworzyć bazy danych konta</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Autoryzacja wygasła, proszę zalogować się ponownie</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation>Nie udało się usunąć tokena synchronizacji lokalnego repozytorium: %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation>Nie udało się pobrać informacji synchronizacji z serwera: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Ustawienia konta</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Proszę podać adres serwera</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 nie jest poprawnym adresem serwera</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Nie udało się zapisać informacji o koncie</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Nie udało się zapisać zmian: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Pomyślnie zaktualizowano dane obecnego konta</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Adres serwera</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>E-mail</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>Czy na pewno chcesz usunąć konto %1?&lt;br&gt;&lt;br&gt;Konto zostanie usunięte tylko lokalne wraz ze wszystkimi ustawieniami synchronizacji. Konto na serwerze pozostanie nietknięte.</translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Nie udało się odsynchronizować bibliotek konta: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>kliknij, aby otworzyć witrynę</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>wersja pro</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Brak konta</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Wybierz</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Ustawienia konta</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Zaloguj</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Usuń</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Dodaj konto</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Wyloguj</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>niezalogowany</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formularz</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Konto</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>adres e-mail</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>serwer</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Aktywności pliku są obsługiwane wyłącznie przez %1 Server Professional Edition.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>ponów</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Nie udało się uzyskać informacji o aktywnościach. Proszę %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Przesyłanie zakończone powodzeniem</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Plik &quot;%1&quot;
+przesyłanie udane.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Plik &quot;%1&quot;
+nieudane przesyłanie.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Brak dostępu!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autoryzacja wygasła</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Plik nie istnieje</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation>Plik jest zablokowany przez %1, proszę spróbować później</translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Niepowodzenie wgrywania: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Nie udało się utworzyć katalogu awatarów</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Sprawdzanie uprawnień</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Zadania pobierania</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>usuń wszystkie zakończone zadania</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Brak zadań pobierania.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Wyczyść</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zamknij</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Biblioteka</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Ścieżka</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Anuluj to zadanie</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>anuluj to zadanie</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Usuń to zadanie</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Nie udało się anulować tego zadania:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Nie udało się usunąć tego zadania:
+
+ %1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimalizuj</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zamknij</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Biblioteki</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Ulubione</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Aktywności</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Szukaj</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>aktualna prędkość pobierania</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>aktualna prędkość wysyłania</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Wybierz folder do synchronizacji</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>brak połączenia z serwerem</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>wszystkie serwery są podłączone</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>niektóre serwery nie zostały podłączone</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formularz</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimalizuj</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>zamknij</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Wybierz</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>brand</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>lub upuść folder, aby zsynchronizować</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>prędkość pobierania</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>strzałka w dół</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>prędkość wysyłania</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>strzałka w górę</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Błąd podczas tworzenia konfiguracji ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Nie można utworzyć wstępnie skonfigurowanego folderu &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>nie udało się odczytać %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Utwórz bibliotekę</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Proszę wybrać folder</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Tworzenie...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Nie udało się wygenerować klucza szyfrowania dla tej biblioteki</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Proszę wybrać folder do synchronizacji</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Folder %1 nie istnieje</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Proszę podać nazwę</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Proszę podać hasło</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Hasła się nie zgadzają</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Nieznany błąd</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Nie udało się dodać zadania pobierania:
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Nie udało się utworzyć biblioteki na serwerze:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Ścieżka:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Wybierz</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nazwa:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>zaszyfrowana</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Hasło:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Powtórz hasło:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>tekst statusu</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>nie można zainicjować klienta %1</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>%1 zakończył się niespodziewanie</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Proszę podać hasło</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Synchronizuj bibliotekę &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Synchronizuj folder &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Synchronizuj do folderu:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>lub</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>synchronizuj z istniejącym folderem</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>utwórz nowy folder synchronizacji</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Synchronizuj z tym istniejącym folderem:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Proszę wybrać folder</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>Folder nie istnieje</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Proszę wybrać folder do synchronizacji.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Twoja organizacja nie pozwala na umieszczanie biblioteki poza folderem %1.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Konflikt z istniejącym plikiem &quot;%1&quot;, proszę wybrać inny folder.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Konflikt z istniejącą biblioteką &quot;%1&quot;, proszę wybrać inny folder.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>Folder &quot;%1&quot; już istnieje. Na pewno chcesz z nim synchronizować (zawartość zostanie połączona)?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Kliknij Nie, aby synchronizować z nowym folderem</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Nie można odnaleźć alternatywnej nazwy folderu</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Nie udało się dodać zadania pobierania:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Nie udało się uzyskać informacji o pobieraniu repozytorium:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Pobierz bibliotekę</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>wybierz...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Hasło do tej biblioteki:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Szczegóły zmian</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Dodane pliki</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Usunięte pliki</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Zmienione pliki</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Dodane foldery</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Usunięte foldery</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Otwórz</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Otwórz folder nadrzędny</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Przeglądarka plików w chmurze</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Wstecz</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Naprzód</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Strona główna</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Wyślij pliki</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Wyślij folder</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Nie masz uprawnień do przesyłania plików do tej biblioteki</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Utwórz folder</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Odśwież</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 elementów</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Nazwa folderu</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Nieprawidłowa nazwa folderu!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>Nazwa &quot;%1&quot; jest już zajęta.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>ponów</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Nie udało się pobrać informacji o plikach&lt;br /&gt;Proszę %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>Ten folder jest pusty</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Podaj nazwę pliku do zapisania...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Nie można usunąć pliku &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Podaj ścieżkę do folderu, do którego chcesz zapisać...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Czy chcesz nadpisać istniejący plik &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>Plik &quot;%1&quot; nie został zsynchronizowany</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Plik %1 już istnieje.&lt;br/&gt;Chcesz go nadpisać?&lt;br/&gt;&lt;small&gt;(Wybierz Nie, aby zapisać go pod inną nazwą).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Plik nie istnieje</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Nie udało się pobrać pliku: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Wybierz plik do przesłania</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Wybierz folder do wysłania</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Zmień nazwę</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Czy na pewno chcesz usunąć te elementy</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Tworzenie folderu nie powiodło się</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Nie udało się zablokować pliku</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Wybierz plik do aktualizacji %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Nie udało się zmienić nazwy</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Nie udało się usunąć</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Nie udało się udostępnić</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Nie można wklejać plików z tego samego folderu</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>Nie można skopiować folderu do jego podfolderu</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Kopiowanie nieudane</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Przenoszenie nieudane</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Nie udało się utworzyć biblioteki!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Nie posiadasz uprawnień do wgrywania do tego folderu</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autoryzacja wygasła</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Brak dostępu!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Nie znaleziono biblioteki/folderu</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation>Nie udało się wgrać pliku %1: %2</translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation>Nie można utworzyć folderu pamięci podręcznej</translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation>Nie można otworzyć folderu pamięci podręcznej</translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Szukaj plików</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Nie udało się pobrać łącza</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>Oczekiwanie</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Wyślij</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Wysyłanie %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Pobierz</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Pobieranie %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 z %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>Nie udało się wgrać pliku &quot;%1&quot;, czy chcesz spróbować ponownie?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>Ponów</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Pomiń</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Przerwij</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>Zapisywanie</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>Nie udało się zapisać pliku</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Nazwa</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Rozmiar</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Ostatnia modyfikacja</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>Pokaż w folderze</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Pokaż w folderze</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Operacja anulowana</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>oczekiwanie</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>anulowano zadanie</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Wewnętrzny błąd serwera</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Dostępna przestrzeń dyskowa została wykorzystana</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>zablokowany przez %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Nazwa</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Rozmiar</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Ostatnia zmiana</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation>Modyfikujący</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>Zapi&amp;sz jako...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>Zab&amp;lokuj</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>Zmień nazwę</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>Usuń</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Udostępnij grupie</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>Akt&amp;ualizuj</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Kopiuj</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Wy&amp;tnij</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Wklej</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Anuluj pobi&amp;eranie</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Synchronizuj ten folder</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Ta funkcja jest dostępna wyłącznie w wersji pro
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>Wy&amp;generuj łącze pobierania %1</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Udostępnij użytkownikowi</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>Wyg&amp;eneruj %1 wewnętrzne łącze</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>Zapi&amp;sz jako do...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Odb&amp;lokuj</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Nie można usunąć plików tylko do odczytu</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Nie można uciąć plików tylko do odczytu</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>Ponów wysyłanie</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>Usuń wersję lokalną</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>Zapisz lokalną wersję jako...</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation>Otwórz lokalny folder pamięci podręcznej</translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Nie udało się pobrać łącza</translation>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Nie udało się utworzyć folderów</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Nie udało się utworzyć plików tymczasowych</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Nie udało się zapisać pliku na dysku</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Nie udało się usunąć starszej wersji pobranego pliku</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Nie udało się przenieść pliku</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>Inicjowanie %1</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Wybierz %1 folder</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Proszę wybrać folder</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Inicjowanie nie zostało zakończone: Na pewno wyjść?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Folder %1 nie istnieje</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Wybierz folder</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Proszę wybrać folder wewnątrz którego zostanie utworzony podfolder %1. Gdy pobierzesz bibliotekę, zostanie ona tam domyślnie zapisana.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Wybierz...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Następny</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1 organizuje pliki w biblioteki.
+Czy chcesz pobrać swoją domyślną bibliotekę?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Sprawdzanie Twojej biblioteki domyślnej...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Tworzenie biblioteki domyślnej...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Nie udało się utworzyć biblioteki domyślnej:
+
+Wymagany serwer w wersji 2.1 lub nowszy.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Nie udało się pobrać biblioteki domyślnej:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Nie udało się utworzyć biblioteki domyślnej:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Pobieranie biblioteki domyślnej...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Nie udało się pobrać biblioteki domyślnej:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Biblioteka domyślna została pobrana.
+Kliknij przycisk &quot;Otwórz&quot;, aby ją wyświetlić.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Błąd podczas pobierania biblioteki domyślnej: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Nie udało się pobrać biblioteki domyślnej:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1 organizuje pliki w biblioteki.
+Czy chcesz pobrać swoją domyślną bibliotekę?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Pomiń</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Uruchom w tle</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Otwórz</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Zakończ</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Pobierz bibliotekę domyślną</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Tak</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>wczytaj więcej</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>Nie udało się wysłać logów</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Wyślij logi</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Brak dostępu!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Nie znaleziono biblioteki/folderu</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autoryzacja wygasła</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>Nie udało się wysłać logów: %1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>Pomyślnie wysłano logi</translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>Kompresowanie</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 z %2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Dodaj konto</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>Pojedyncze logowanie</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Zaloguj ponownie</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Logowanie...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Błąd sieci:
+ %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Ostrzeżenie:&lt;/b&gt; Certyfikat SSL tego serwera nie jest zaufany, kontynuować?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Podaj adres serwera</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 nie jest prawidłowym adresem serwera</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Proszę podać nazwę użytkownika</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Podaj nazwę komputera</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Nie udało się zapisać aktualnego konta</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>Adres serwera %1</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>Adres serwera nie może być pusty</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1 nie jest prawidłowym adresem serwera. Adres musi się zaczynać od &apos;https://&apos;</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Proszę podać hasło</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Nieprawidłowy adres e-mail lub hasło</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Zbyt częste próby logowania, proszę chwilę odczekać</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Wewnętrzny błąd serwera</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Niepowodzenie logowania: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Niepowodzenie logowania</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Serwer:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Na przykład: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>lub http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Hasło:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>tekst statusu</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Nazwa komputera:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Email / Nazwa użytkownika:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>np. laptop Kuby</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Zaloguj</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Logowanie automatyczne</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Jesteś wylogowany. Proszę</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>zaloguj</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Dodaj konto</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Odśwież</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation>&quot;%1&quot; jest niezsynchronizowana.
+Powód: Usunięta na serwerze</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation>&quot;%1&quot; jest zsynchronizowana</translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation>Pliki przesłane do &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation>Konflikt pliku %1</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation>Nie udało się zsynchronizować pliku %1
+Plik jest zablokowany przez inną aplikację, będzie przesłany, gdy zostanie ona zamknięta.</translation>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation>Nie udało się zsynchronizować folderu %1
+Jeden z plików wewnątrz tego folderu jest zablokowany przez inną aplikację. Folder zostanie zaktualizowany, gdy ją zamkniesz.</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation>Nie udało się zsynchronizować pliku %1
+Plik jest zablokowany przez innego użytkownika. Zmiany w tym pliku nie są synchronizowane.</translation>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation>Nie udało się zindeksować pliku %1
+Proszę sprawdzić uprawnienia do pliku i dostępną przestrzeń dyskową.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation>Nie udało się zsynchronizować %1
+Ścieżka pliku jest zakończona spacją lub kropką i nie może być utworzona w systemie Windows</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation>Nie udało się zsynchronizować %1
+Ścieżka do pliku zawiera nieprawidłowe znaki. Plik nie jest synchronizowany z tym komputerem.</translation>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation>Aktualizacja pliku %1 jest niemożliwa z powodu aktualnej konfiguracji praw dostępu do katalogu.</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation>&quot;%1&quot; nie udało się zsynchronizować. 
+Brak dostępu do usługi</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation>&quot;%1&quot; nie udało się zsynchronizować.
+Wolna przestrzeń właściciela biblioteka została wykorzystana.</translation>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Udostępnij %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Podaj nazwę grupy</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Podaj nazwę użytkownika lub adres email</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Pomyślnie zaktualizowano</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>Niepowodzenie udostępniania: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Pomyślnie usunięto</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Nie udało się uzyskać informacji udostępniania folderu</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Nie udało się uzyskać informacji o grupach i kontaktach</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Proszę podać nazwę użytkownika</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Proszę podać nazwę grupy</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>Grupa &quot;%1&quot; nie istnieje</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Już udostępniono grupie %1</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Już udostępniono użytkownikowi %1</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Poprzednia operacja ciągle trwa</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Udostępnij dla:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Udostępnij</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Uprawnienia:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Odczyt-Zapis</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Tylko-odczyt</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zamknij</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>zsynchronizowano</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indeksowanie plików</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>inicjowanie synchronizacji</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>pobieranie</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>wysyłanie</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>scalanie synchronizacji</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>oczekiwanie na synchronizację</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>serwer nie podłączony</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>uwierzytelnianie serwera</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>synchronizacja automatyczna jest wyłączona</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>nieznany</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Serwer został usunięty</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Nie zalogowałeś się do serwera</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Nie masz praw dostępu do tej biblioteki</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Wolna przestrzeń właściciela biblioteki została wykorzystana</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Zdalna usługa jest niedostępna</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Brak dostępu do usługi</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Dane wewnętrzne uszkodzone</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Nie udało się rozpocząć wysyłania</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Nie udało się rozpocząć pobierania</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Biblioteka na serwerze jest uszkodzona</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Konflikt scalania</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Wersja serwera jest zbyt stara</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Nieznany błąd</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Błąd sieci</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>Nie można ustalić adresu serwera proxy</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>Nie można ustalić adresu serwera</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>Nie można połączyć się z serwerem</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>Nie udało się nawiązać bezpiecznego połączenia. Proszę sprawdzić certyfikat SSL serwera.</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation>Transfer został przerwany. Proszę sprawdzić połączenie z siecią lub zaporę</translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation>Przekroczony czas transferu. Proszę sprawdzić połączenie z siecią lub firewall</translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation>Nieobsługiwane przekierowanie http z serwera. Proszę sprawdzić konfigurację serwera.</translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Błąd serwera</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Złe żądanie</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>Brak pamięci</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation>Nie udało się zapisać danych po stronie klienta. Proszę sprawdzić ilość dostępnego miejsca lub uprawnienia do folderu</translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>Wolne miejsce zostało wykorzystane</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>Biblioteka została usunięta z serwera</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>Biblioteka na serwerze jest uszkodzona</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Dostępne miejsce zostało wykorzystane</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Wewnętrzny błąd serwera</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Twój klient %1 jest za stary</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Nie udało się zsynchronizować biblioteki</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Pliki są zablokowane przez inną aplikację</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Biblioteka na serwerze została usunięta</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Błąd podczas próby dostępu do lokalnego folderu</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>inicjowanie...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>Nie udało się zindeksować plików lokalnych</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>Nie udało się sprawdzić informacji serwera</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>Nie udało się utworzyć plików lokalnych</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>Nie udało się scalić zmian lokalnego pliku</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Nieprawidłowe hasło. Proszę pobrać ponownie</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Błąd wewnętrzny</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>łączenie z serwerem...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indeksowanie plików...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Pobieranie listy plików...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Pobieranie plików...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Tworzenie folderu...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Scal zmiany pliku</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Zakończone</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>sprawdzanie informacji serwera...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Anulowanie</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Anulowano</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>Błąd SSL</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Błąd sieci: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Błąd serwera</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>nie udało się otworzyć bazy certyfikatów</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>Plik &quot;%1&quot; nie istnieje w &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 nie może odnaleźć aplikacji do otwarcia pliku %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Utworzona biblioteka &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Usunięta biblioteka &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Zmień nazwę %1 na</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Nie można pobrać elementu &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>nie udało się skopiować</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Dodano</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Usunięto</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Usunięto</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Zmieniono</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Zmieniono nazwę</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Dodane lub zmienione</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Przeniesiono</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Dodano folder</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Usunięto folder</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Zmieniono nazwę folderu</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Przeniesiono folder</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>pliki</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>foldery</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>i %1 więcej</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Przywrócono bibliotekę do stanu z</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Przywrócono plik &quot;%1&quot; do stanu z %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Odzyskano usunięty folder</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Zmieniono nazwę lub opis biblioteki</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>Automatyczne scalanie przez %1 system</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>przed chwilą</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>wczoraj</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 dni temu</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>godzinę temu</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 godzin temu</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>minutę temu</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 minut temu</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Nie jest częścią certyfikatu&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Synchronizuj tę bibliotekę z:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Synchronizuj ten folder z:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Folder</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Folder tylko do odczytu</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Dokument</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>Dokument PDF</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Plik graficzny</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Plik tekstowy</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Plik audio</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Plik wideo</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Dokument Word</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>Dokument PowerPoint</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Dokument Excel</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>Ścieżka &quot;%1&quot; jest w konflikcie ze ścieżką systemową</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>Ścieżka &quot;%1&quot; jest w konflikcie z istniejącą biblioteką</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>przesyłanie listy plików</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>Plik jest zablokowany przez inną aplikację</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>Folder jest zablokowany przez inną aplikację </translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>Plik jest zablokowany przez innego użytkownika</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>Ścieżka jest nieprawidłowa</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Błąd podczas indeksowania</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>Ścieżka jest zakończona spacją lub kropką</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>Ścieżka zawiera nieprawidłowe znaki, np. &quot;|&quot; lub &quot;:&quot;</translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation>nie udało się otworzyć podręcznej bazy plików</translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation>Nazwa biblioteki zawiera nieprawidłowe znaki, takie jak &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation>Aktualizacja pliku jest niemożliwa z powodu aktualnej konfiguracji praw dostępu do katalogu</translation>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation>%1 Client jest już uruchomiony</translation>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation>Wystąpił błąd podczas wysyłania.</translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation>Wystąpił błąd podczas pobierania.</translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation>Brak uprawnień do synchronizacji tego folderu</translation>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>Plik nie istnieje</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Biblioteka &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Ta biblioteka nie została jeszcze pobrana</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Błąd:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>co %1 sekund</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Ikona repozytorium</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>Nazwa repozytorium</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Etykieta tekstowa</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Właściciel:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Ostatnia zmiana:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Rozmiar:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Ścieżka lokalna:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Status:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Status repozytorium</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nazwa:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Interwał synchronizacji:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zamknij</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Ta biblioteka nie została pobrana</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>Nie można otworzyć pliku &quot;%1&quot; z nieistniejącej biblioteki &quot;%2&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Ostatnio aktualizowane</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Moje biblioteki</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Biblioteki podrzędne</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Udostępnione mnie</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Udostępnione wszystkim</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Udostępnione grupom</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Zsynchronizowane biblioteki</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>inicjowanie synchronizacji</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Wyłącz auto synchronizację</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Włącz auto synchronizację</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Pokaż &amp;szczegóły</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Pokaż szczegóły tej biblioteki</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Synchronizuj tę bibliotekę</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Synchronizuj tę bibliotekę</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Ostatnio zaktualizowane</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Sy&amp;nchronizuj teraz</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Niezwłocznie synchronizuj tę bibliotekę</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>Anuluj pobieranie (&amp;C)</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Anuluj pobieranie tej biblioteki</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Otwórz folder</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>otwórz folder lokalny</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>&amp;Otwórz folder lokalny</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>Wyłącz synchronizację (&amp;U)</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>wyłącz synchronizację tej biblioteki</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>Pokaż  w chmurze (&amp;V)</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>pokaż tę bibliotekę w seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Udostępnij użytkownikowi</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Udostępnij tę bibliotekę użytkownikowi</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Udostępnij grupie</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Udostępnij tę bibliotekę grupie</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Otwórz przeglądarkę plików w chmurze</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>otwórz tę bibliotekę we wbudowanej przeglądarce plików w chmurze</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>Opuść udzia&amp;ł</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>opuść udział</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>Synch&amp;ronizuj tę bibliotekę ponownie</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>przestań synchronizować, a następnie ponownie zsynchronizuj tę bibliotekę</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Ustaw &amp;interwał synchronizacji</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation>ustaw interwał synchronizacji dla tej biblioteki</translation>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation>Czy na pewno chcesz przestać synchronizować bibliotekę&quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation>Czy na pewno chcesz ponowić synchronizację biblioteki &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation>Czy na pewno chcesz nadpisać plik &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Nie udało się wyłączyć synchronizacji biblioteki &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation>Czy na pewno chcesz opuścić udział &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation>Nie udało się opuścić udziału</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Nie udało się anulować tego zadania:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Pobieranie zostało anulowane</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>Nie masz uprawnień do przesyłania plików do tego folderu</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>Nie można nadpisać pliku &quot;%1&quot; nim samym</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Nie można usunąć pliku &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Nie udało się wgrać pliku: &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Interwał synchronizacji (w sekundach):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Ustaw interwał synchronizacji dla biblioteki &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>Przeszukaj biblioteki</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>ponów</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Nie udało się uzyskać informacji o bibliotekach&lt;br/&gt;Proszę %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Ostrzeżenie:&lt;/b&gt; Certyfikat SSL tego serwera nie jest zaufany, kontynuować?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>nie udało się dodać konta domyślnego</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Nie udało się zainicjować logu: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Tak</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nie</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation>nie udało się zapisać id klienta</translation>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation>nie udało się uzyskać dostępu do %1</translation>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation>nieprawidłowe id klienta</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>nie udało się odczytać %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>Łącze wewnętrzne %1</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Kopiuj do schowka</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation>Łącze wewnętrzne %1:</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Nieznany błąd</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation>błąd wewnętrzny: nie udało się połączeń z demonem</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Wyłącz auto synchronizację</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Włącz auto synchronizację</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>Wyjdź (&amp;Q)</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Pokaż główne okno</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Ustawienia</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Otwórz &amp;folder %1</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>otwórz folder %1</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Otwórz folder z &amp;logami</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>Pokaż błędy synchronizacji pliku</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>O progr&amp;amie</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Pokaż okno &quot;O programie&quot;</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>Pomoc &amp;online</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Plik</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>synchronizacja automatyczna jest wyłączona</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Wysyłanie</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Pobieranie</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>otwórz folder z logami %1</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>otwórz pomoc online %1</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>niektóre serwery nie zostały podłączone</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Wyślij pliki logów</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>wyślij %1 logów</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>Proszę najpierw się zalogować</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>Pokaż w folderze</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Pokaż w folderze</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>Szukaj plików</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>ponów</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Nie udało się wyszukać&lt;br/&gt;Proszę %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Status połączeń serwerów</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>połączono</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>rozłączono</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zamknij</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Proszę podać hasło do biblioteki</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Proszę podać hasło do biblioteki %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Proszę podać hasło</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Nieprawidłowe hasło</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Nieznany błąd</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Ustawienia</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>Automatycznie uruchom %1 po zalogowaniu</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>Ukryj ikonę %1 w doku</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Brak</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>Proxy HTTP</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Proxy Socks5</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Systemowy serwer pośredniczący</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Zmieniono język. Zrestartować aplikację, aby wprowadzić zmiany?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>Adres serwera pośredniczącego nie może być pusty</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>Port serwera pośredniczącego jest nieprawidłowy</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>Nazwa użytkownika serwera pośredniczącego nie może być pusta</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>Hasło serwera pośredniczącego nie może być puste</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Ukryj główne okno podczas uruchamiania</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Powiadom, gdy biblioteki są zsynchronizowane</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Synchronizuj pliki tymczasowe MSOffice/LibreOffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Ogranicz prędkość pobierania (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Ogranicz prędkość wysyłania (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Podstawowe</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Nie wyłączaj automatycznie synchronizacji bibliotek</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Nie wyłączaj automatycznie synchronizacji biblioteki, gdy jej folder lokalny zostanie usunięty lub z innych przyczyn stanie się nieosiągalny.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Nie wyłączaj synchronizacji brakującej na serwerze biblioteki</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Nie wyłączaj automatycznie synchronizacji biblioteki, gdy ta nie zostanie znaleziona na serwerze</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Włącz rozszerzenie FinderSync</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Włącz rozszerzenie Explorera</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>Sprawdzaj aktualizacje automatycznie</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Nie weryfikuj certyfikatu serwera podczas synchronizacji przez HTTPS</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Włącz synchronizację z istniejącym folderem o innej nazwie</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Zaawansowane</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Język (wymaga restartu)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Język</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Rodzaj proxy:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Host:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Port:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Nazwa użytkownika:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Hasło:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Serwer proxy wymaga hasła</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Sieć</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Odczyt i zapis</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Tylko odczyt</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Usuń udział</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>Kliknij, aby edytować</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Utworzony przez %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Odczyt i zapis</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Tylko odczyt</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Grupa</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Użytkownik</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Uprawnienia</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Poprzednia operacja ciągle trwa</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Łącze udostępniania</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Łącze udostępniania:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Pobieranie bezpośrednie</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Kopiuj do schowka</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Niezaufane połączenie</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 używa nieprawidłowego certyfikatu. Połączenie może nie być bezpieczne. Czy chcesz kontynuować?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Obecny odcisk palca klucza RSA to %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Poprzedni odcisk palca klucza RSA to %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Zapamiętaj mój wybór</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Tak</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nie</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Otwórz</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Otwórz ten plik</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>&amp;wyświetl w sieci</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>wyświetl ten plik w przeglądarce</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>ponów</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Nie udało się uzyskać informacji o ulubionych plikach&lt;br/&gt;Proszę %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Nie masz ulubionych plików.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Błędy Synchronizacji Pliku</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>Brak błędów synchronizacji.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Kliknij dwukrotnie, aby otworzyć bibliotekę</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Biblioteka</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Ścieżka</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Błąd</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Czas</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation>Wpisz token uwierzytelniania dwuskładnikowego</translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation>Uwierzytelnianie dwuskładnikowe</translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation>Proszę wpisać token uwierzytelniania dwuskładnikowego</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mText</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>Zapamiętaj to urządzenie</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Anuluj</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Odinstaluj %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Czy chcesz usunąć informacje o koncie %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Usuwanie informacji o koncie...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>tekst</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Tak</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nie</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_pt_BR.ts b/i18n/seafile_pt_BR.ts
new file mode 100644 (file)
index 0000000..99769e7
--- /dev/null
@@ -0,0 +1,3295 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="pt_BR" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>Sobre %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 Cliente %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; REV %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>Sobre</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Verificar Atualizações</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>falha ao abrir o banco de dados de contas</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>A autorização expirou. Por favor, faça o autentique-se novamente.</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation>Falha ao remover repositório local token de sincronização: %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Configurações da Conta</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Por favor, informe o endereço do servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 não é um endereço válido de servidor</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Falhou ao salvar as informações da conta</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Falou ao salvar as modificações: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Atualização com sucesso das informações da conta atual</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Endereço do Servidor</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Email</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Falhou ao dessincronizar as bibliotecas desta conta: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>clique para abrir o site</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>Versão Pro</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Sem conta</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Escolha</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Configurações da conta</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Login</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Apagar</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Incluir uma conta</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Sair</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>Não conectado</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>De</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Conta</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>email</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>servidor</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Atividades de Arquivo são somente suportadas no %1 Servidor Edisão Profissional.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>tentar novamente</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Falhou ao obter informações de atividades. Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Envio de arquivo com sucesso</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Arquivo &quot;%1&quot;
+enviado com sucesso.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Arquivo &quot;%1&quot;
+falhou ao enviar.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Erro de Permissão!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Autorização expirada</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Arquivo nãoexiste</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation>O arquivo está bloquado por %1, favor tente mais tarde</translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Falha no Upload: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Falhou ao criar pasta de avatares</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Verificando Permissão</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Tarefas de download</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>todas as tarefas removidas com sucesso</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Sem tarefas de download no momento</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Limpar</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fechar</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Biblioteca</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Caminho</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Cancelar esta tarefa</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>cancela esta tarefa</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Remover esta tarefa</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Falha ao cancelar esta tarefa:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Falha ao remover esta tarefa:
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimizar</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fechar</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Bibliotecas</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Estrelado</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Atividades</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Procurar</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>taxa atual de download</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>taxa atual de upload</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Favor escolher uma pasta para sincronizar</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>sem servidor conectado</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>todos os servidores conectados</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>alguns servidores não estão conectados</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulário</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimizar</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>fechar</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Selecionar</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>marca</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>ou Solte a Pasta aqui para Sincronizar</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>taxa de download</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>downarrow</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>taxa de upload</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>uparrow</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Erro ao criar a configuração ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Não foi possivel criar um diretorio pré-configurado &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>falla ao ler %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Criar uma biblioteca</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Por favor escolha uma pasta</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Criando...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Falha ao gerar chave de encriptação para essa biblioteca</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Por favor escolha uma pasta para sincronizar</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>A pasta %1 não existe</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Por favor informe o nome</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Por favor informe a senha</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>As senhas não batem</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Erro deconhecido</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Falha ao incluir a tarefa de download:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Falhou ao criar biblioteca no servidor:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Caminho:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Escolher</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nome:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>encriptado</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Senha:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Senha de novo:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>texto de status</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>%1 cliente falhou ao inicializar</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>%1 saiu inesperadamente</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Por favor informe a senha</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Sincronizar biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Sincronizar pasta &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Sincronizar para a pasta:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>ou</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>sincronizar com uma pasta existente</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>criar uma nova pasta de sincronização</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Sincronizar com uma pasta existente:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Por favor, escolha uma pasta</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>A pasta não existe</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Por favor, escolha a pasta para sincronizar.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Sua organização desabilitou colocando uma biblioteca fora da 1% pasta.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflito com um arquivo existente &quot;%1&quot;. Por favor, escolha uma pasta diferente.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Conflito com uma biblioteca existente &quot;%1&quot;. Por favor, escolha uma pasta diferente.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>A pasta &quot;% 1&quot; já existe. Tem certeza que deseja sincronizar com ele ( os conteúdo serão mesclados ) ?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Clique em Não para sincronizar com  a nova pasta.</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>
+Incapaz de encontrar um nome alternativo para a pasta</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Falha ao incluir a tarefa de baixar:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Falha ao obter informação de descarga do repositório:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Biblioteca de download</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>escolher...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Senha para esta biblioteca:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Detalhes da Modificação</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Arquivos Adicionados</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Arquivos Apagados</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Arquivos Modificados</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Pastas adicionadas</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Pastas apagadas</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Abrir</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Abrir pasta &amp;pai</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Navegado de Arquivos na Nuvem</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Voltar</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Avançar</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Início</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Enviar arquivos</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Enviar um diretório</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Você não tem permissões para enviar arquivos para esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Criar uma pasta</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Recarregar</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 itens</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Nome da pasta</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Nome de pasta inválido!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>O nome &quot;%1&quot; já está sendo utilizado.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>tentar novamente</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Falha ao obter informações dos arquivos&lt;br/&gt;Por favor %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>Esta pasta está vazia.</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Digite o nome do arquivo para salvar em...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Não foi possível remover o arquivo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Digite o caminho da pasta que você deseja salvar em ...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Você deseja substituir o arquivo existente &quot;% 1&quot;?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>Arquivo &quot;%1&quot; não foi  sincronizado</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>O arquivo %1 já existe.&lt;br/&gt;Você gostaria de sobrescrever ele?&lt;br/&gt;&lt;small&gt;(Escolha Não para enviar utilizando um nome alternativo)</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Arquivo não existe</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Falha ao descarregar o arquivo: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Selecione um arquivo a enviar</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Selecione um diretório para fazer o envio</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Renomear</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Você realmente quer apagar estes itens</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Criação de pasta falhou</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Falha ao fechar arquivo</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Selecione um arquivo para enviar %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Renomear falhou</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Remover falhou</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>O compartilhamento falhou</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Não é possível colar arquivos na mesma pasta</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Copiar falhou</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Mover falhou</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Falha ao criar biblioteca!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Enviar arquivo</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Enviando %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Descarregar</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Descarregando %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 de %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Operação cancelada</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>pendente</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Erro Interno do Servidor</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>Travado por %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Nome</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Tamanho</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Última Alteração</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Salvar Como...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>&amp;Trancar</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Renomear</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Deletar</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Compartilhar com Grupo</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>At&amp;ualizar</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Copiar</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Cor&amp;tar</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>C&amp;olar</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>Canc&amp;elar o Descarregamento</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Sincronizar esta pasta</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Esta característica está disponível somente na versão pro
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>&amp;Gerar %1 Link de Download</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Compartilhar com Usuário</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>G&amp;erar %1 Link interno</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Salvar Como...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Des&amp;Travar</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Não é Possivel remover arquivos somente leitura</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Não é possivel recortar arquivos somente leitura</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Falha ao criar pastas</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Falha ao criar arquivos temporários</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Falha ao gravar o arquivo no disco</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Falha ao remover a versão antiga do arquivo descarregado</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Falha ao mover o arquivo</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 inicializado</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Escolher %1 pasta</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Por favor escolher uma pasta</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>A inicialização não terminou. Realmente quer sair?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>A pasta %1 não existe</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logotipo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Escolher pasta</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Por favor, escolha uma pasta. Nos criaremos uma %1 subpasta para ela. Quando você descarregar uma biblioteca, ela será salva lá por padrão.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Escolher...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Próximo</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Checando sua biblioteca padrão...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Criando biblioteca default...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Falhou ao criar a biblioteca padrão:
+
+A versão do servidor necessita ser 2.1 ou maior para suportar isto.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Falha ao pegar a biblioteca padrão:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Falha ao criar a biblioteca padrão:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Baixando biblioteca default...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Falha ao descarregar a biblioteca padrão:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>A biblioteca padrão foi descarregada.
+Você pode clicar no botão &quot;Abrir&quot; para vê-la.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Erro enquanto descarregava a biblioteca padrão: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Falha ao descarregar a biblioteca padrão:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>omitir</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Executar em segundo plano</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Abrir</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Finalizar</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Baixar biblioteca default</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sim</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logotipo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Incluir uma conta</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Re-conectar</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Logando em...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Erro de Rede:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt; Aviso: &lt;/ b&gt; O certificado SSL deste servidor não é confiável, continuar assim mesmo?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Favor informar o endereço do servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 não é um endereço do servidor válido</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Por favor informe o nome do usuário</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Por favor, digite o nome do computador</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Falha ao salvar a conta atual</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Favor informa a senha</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Email ou senha incorreta</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Conectando muito frequentemente, por favor, espere um minuto</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Erro Interno do Servidor</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Falla ao logar: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Falla ao logar</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logotipo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Servidor:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Por exemplo: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>ou http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Senha:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>texto de status</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Nome do Computador:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Email / Usuário</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>e.x: Computador do Giba</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Login</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Deslogue-se Por Favor</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>Login</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Adicionar uma conta</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Atualizar</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Compatilhar %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Por favor informe o nome do grupo</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Atualizado com sucesso</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Removido com sucesso</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Falhou ao obter informação compartilhado da pasta</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Falha ao obter informação do seu grupo e contatos</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Por favor informe o nome do usuário</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>sincronizado</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indexando arquivos</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>incializando sincronismo</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>baixando</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>subindo</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>mesclando</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>esperando sincronismo</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>servidor não conectado</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>autenticando servidor</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>auto sincronismo desligado</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>desconhecido</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>O Servidor foi removido</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Você não conectou-se ao servidor</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Você não tem permissão para acessar esta biblioteca </translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>O espaço de armazenamento do dono da biblioteca acabou</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Serviço remoto não disponível</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Acesso negado ao serviço.</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Dados internos corrompidos.</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Falha ao iniciar o envio de arquivo</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Falha ao iniciar o descarregamento</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>A biblioteca está danificada no servidor</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Conflito ao mesclar</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>A versão do servidor é muito antiga</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Erro desconhecido</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>A cota de armazenamento foi toda utilizada</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Erro interno do servidor</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Seu cliente %1 é muito antigo</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Falha ao sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Os arquivos estão bloqueados por outra aplicação</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>A biblioteca foi removida do servidor</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Erro enquanto acessava a pasta local</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>inicializando...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>conectando ao servidor...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indexando arquivos...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Criando pasta...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Mesclando arquivos modificados...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Feito</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Cancelando</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Cancelado</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>Erro de SSL</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Erro de Rede: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Erro do Servidor</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>falha ao abrir o banco de dados de certificados</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>Arquivo &quot;%1&quot; não existe em &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 não pode encontrar uma aplicação para abrir o arquio %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Biblioteca criada &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Biblioteca apagada &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Renomear %1 para</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Não foi possível descarregar o item &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>falha ao copiar</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Adicionado</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Apagado</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Removido</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Modificado</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Renomeado</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Adicionado ou modificado</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Movido</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Diretório adicionado</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Diretório removido</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Diretório renomeado</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Diretório movido</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>arquivos</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>diretórios</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>e %1 mais</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Biblioteca revertida para o estado em</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Arquivo revertido &quot;%1&quot; para o estado em %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Diretório apagado recuperado</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Nome da biblioteca  ou descrição modificada</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Agora</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1 dia atrás</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 dias atrás</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1 hora atrás</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 horas atrás</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1 minuto atrás</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 minutos atrás</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Não faz parte do certificado&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Sincronizar esta biblioteca com:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Sincronizar esta pasta com:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Pasta</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Pasta somente leitura</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Documento</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>Documento PDF</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Arquivo de Imagem</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Documento de Texto</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Arquivo de Audio</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Arquivo de Video</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Documento Word</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>Documento PowerPoint</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Documento Excel</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>O caminhho &quot;%1&quot; conflita com o caminho do sistema</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>O caminhho &quot;%1&quot; conflita com uma biblioteca existente</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Biblioteca %1</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Esta biblioteca não foi baixada ainda</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Erro:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Icone do Repo</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>Nome do Repositório</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Etiqueta</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Dono:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Última Modificação:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Tamanho:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Caminho Local:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Status:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Status Repo</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nome:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fechado</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Esta biblioteca não foi baixada</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>Não foi possível abrir o arquivo &quot;% 1&quot; da biblioteca inexistente &quot;% 2&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Recentemente Atualizado</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Minhas bibliotecas</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Sub-Bibliotecas</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Bibliotecas sincronizadas</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>inicializando sincronismo</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desabilitar auto sincronismo</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Habilitar auto sincronismo</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Exibir &amp;detalhes</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Exibir detalhes desta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>Sincroni&amp;zar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Sincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Recentemente Atualizado</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Si&amp;ncronizar agora</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Sincronizar esta biblioteca imediatamente</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Cancelar download</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Cancelar download desta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Abrir pasta</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>abrir pasta local</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Desincronizar</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>desincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Ver na nuvem</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>ver esta biblioteca em Seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>Abrir &amp;o navegador de arquivos na nuvem</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>abrir esta biblioteca no Navegador de Arquivos na Nuvem</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>&amp;Ressincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>dessincronizar e ressincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Falha ao dessincronizar a biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Falha ao cancelar esta tarefa:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>O download foi cancelado</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>Não é possível substituir o arquivo &quot;% 1&quot; com ele mesmo</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Não foi possível apagar o arquivo &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Falha ao enviar o arquivo: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>tentar novamente</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Falha ao buscar informações da biblioteca&lt;br/&gt;Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt; Aviso: &lt;/ b&gt; O certificado SSL deste servidor não é confiável, continuar assim mesmo?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>Falha ao adicionar conta padrão</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Falho ao inicializar o histórico: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sim</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Não</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copiar para a área de transferência</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Erro desconhecido</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desabilitar auto sincronismo</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Habilitar auto sincronismo</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Sair</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Mostrar janela principal</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Configurações</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Abrir %1 &amp;Pasta</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>abrir %1 &amp;pasta</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Abrir pasta de &amp;históricos</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Sobre</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Mostrar caixa de sobre da aplicação</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Ajuda online</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Arquivo</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>auto sincronismo está desabilitado</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Enviando</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Descarregando</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>abrir %1 &amp;pasta de log</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>
+Abrir % 1 ajuda on-line</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>Alguns servidores não estão conectados</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>retentar</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Falha na busca&lt;br/&gt;Por favor %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Status de conexão dos servidores</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>conectado</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>desconectado</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fechar</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Por favor, forneça uma senha para a biblioteca</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Forneça uma senha para a biblioteca %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Por favor, digite a senha</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Senha incorreta</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Erro desconhecido</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Configurações</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Nenhum</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>Proxy HTTP</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Proxy para Socks5</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Você modificou o idioma. Reiniciar para aplicá-lo?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Ocultar janela principal quando começar</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Notificar quando as bibliotecas estiverem sincronizadas</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Habilitar sincronização de arquivos temporários do MSOffice/LibreOffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Velocidade de descarga (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Velocidade de envio (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Básico</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Não dessincronizar automaticamente uma biblioteca</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Não dessincronizar automaticamente uma biblioteca quando o diretório local dela é removido ou inacessível por outras razões.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Não dessincronizar uma biblioteca quando não encontrada no servidor</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Não dessincronizar automaticamente uma biblioteca quando ela não for encontrada no servidor</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Habilitar a Extensão FinderSync</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Habilitar a Extensão Explorer</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Não verificar o certificado do servidor quando sincronizando por HTTPS</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Ativar a sincronização com uma pasta existente com um nome diferente</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Avançado</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Idioma (necessita reiniciar)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Idioma</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Tipo de Proxy:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Servidor:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Porta:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Nome de usuário:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Senha:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>O servidor proxy requer uma senha</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Rede</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Compartilhar Link</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Compartilhar link:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Download direto</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Copiar para a área de transferência</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Conexão não-confiável</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 utiliza um certificado de segurança inválido. A conexão pode ser insegura. Você quer continuar?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>A chave de impressão digital RSA corrente é %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>A chave de impressão digital RSA anterior é  %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Memorizar minha escolha</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sim</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Não</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Abrir</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Abrir este arquivo</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>exibir na &amp;Web</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>ver este arquivo no site</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>retentar</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Falha ao buscar informações de arquivos estrelados&lt;br/&gt;Por favor %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Você não tem nenhum arquivo estrelado ainda.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Desinstalar %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Você realmente quer remover a informação da conta %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Removendo informações da conta...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>texto</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sim</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Não</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_pt_PT.ts b/i18n/seafile_pt_PT.ts
new file mode 100644 (file)
index 0000000..15bc01c
--- /dev/null
@@ -0,0 +1,3287 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="pt_PT" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>falha ao abrir a base de dados da conta</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Tarefas de descarga</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>remover todas as tarefas de descarregadas com sucesso</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Sem tarefas de descarga neste momento.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Limpar</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fechar</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Biblioteca</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Caminho</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Cancelar esta tarefa</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>cancelar esta tarefa</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Remover esta tarefa</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>O cancelamento desta tarefa falhou:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Falha ao remover esta tarefa:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimizar</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fechar</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>taxa de descarga atual</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>taxa de envio atual</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Por favor escolha uma pasta para sincronizar</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>nenhum servidor ligado</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>todos os servidores conectados</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>alguns servidores desconectados</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulário</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimizar</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>fechar</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Selecionar</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>taxa de descarga</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>taxa de envio</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Erro ao criar configuração de ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>falha na leitura %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Criar uma biblioteca</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Por favor escolha uma pasta</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>A criar...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Por favor escolha uma pasta para sincronizar</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>A pasta %1 não existe</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Por favor introduza o nome</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Por favor introduza a palavra-passe</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Palavras-passe não coincidem</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Erro desconhecido</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Falha ao adicionar as tarefas de download:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Caminho:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Escolha</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nome:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>encriptado</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Palavra-passe:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Palavra-passe Novamente:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>texto de estado</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Por favor introduza a palavra-passe</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Sincronizar biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Falha ao adicionar tarefa de descarga:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Descarregar Biblioteca</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>escolher...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Palavra-passe para esta biblioteca:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 Iniciação</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Por favor escolha uma pasta</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Inicialização não completa. Deseja mesmo sair?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>A pasta %1 não existe</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Escolha...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Próximo</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>A verificar a sua biblioteca pré-definida</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>A criar a biblioteca pré-definida...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Falha ao criar a biblioteca pré-definida:
+
+A versão do servidor deve ser 2.1 ou superior para suportar isto.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>A descarregar a biblioteca pré-definida...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>A biblioteca pré-definida foi descarregada.
+Pode clicar em &quot;Abrir&quot; para visualizar.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Erro a descarregar a biblioteca pré-definida: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Falha ao descarregar a biblioteca pré-definida:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Avançar</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Correr em segundo plano</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Abrir</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Terminar</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Descarregar a biblioteca pré-definida</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sim</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Adicionar uma conta</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>A iniciar sessão...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Erro de rede:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Atenção:&lt;/b&gt; O certificado SSL deste servidor não é confiável, proceder mesmo assim?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Por favor introduza o endereço do servidor</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 não é um endereço de servidor válido</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Por favor introduza um nome de utilizador</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Falha ao guardar conta atual</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Por favor introduza a palavra-passe</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Email ou palavra-passe incorretos</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Erro Interno de Servidor</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Início de sessão falhou: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Início de sessão falhou</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Palavra-passe:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>texto de estado</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Iniciar sessão</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Atualizar</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>sincronizado</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>A indexar ficheiros</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>A iniciar sincronização</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>A descarregar</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>A enviar</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>a fundir sincronização</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>A aguardar sincronização</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>servidor não conectado</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>servidor a autenticar</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>sincronização automática desligada</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>desconhecido</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>O servidor foi removido</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Não iniciou sessão no servidor</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Não tem permissão para aceder a esta biblioteca</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>O espaço do proprietário da biblioteca está a ser utilizado por completo</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Serviço remoto não está disponível</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Biblioteca eliminada no servidor</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>a inicializar...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>a establecer ligação ao servidor...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>a indexar ficheiros...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>A criar pasta...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Fundir alterações de ficheiros...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Concluído</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>A Cancelar</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Cancelado</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Esta biblioteca ainda não foi descarregada</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Erro:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Proprietário:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Alterado pela última vez em:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Tamanho:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Caminho Local:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Estado:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Nome:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fechar</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Esta biblioteca não foi descarregada</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Atualizado Recentemente</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Minha Biblioteca</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Sub-bibliotecas</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desativar sincronização automática</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Ativar sincronização automática</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Sincronizar esta biblioteca imediatamente</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Cancelar descarga</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Cancelar a descarga desta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Abrir pasta</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>abrir pasta local</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Dessincronizar</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>dessincronizar esta biblioteca</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Ver na Cloud</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>ver esta biblioteca no seahub</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Falha ao dessincronizar a biblioteca &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Falha ao cancelar esta tarefa:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>A descarga foi cancelada</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Erro desconhecido</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Desativar sincronização automática</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Ativar sincronização automática</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Sair</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Mostrar janela principal</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Definições</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Sobre</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Mostrar a caixa Sobre da aplicação</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Ajuda online</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>sincronização automática desligada</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>alguns servidores não conectados</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Estado da conexão aos servidores</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>conectado</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>desconectado</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Fechar</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Definições</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Esconder a janela principal no início</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Notificar quando as bibliotecas forem sincronizadas</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Limitar a velocidade de download (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Limite de velocidade de envio (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>0</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Desinstalar %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Deseja remover a informação da conta %1 ?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>A remover informação da conta...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Diálogo</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>texto</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Sim</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Não</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_ru.ts b/i18n/seafile_ru.ts
new file mode 100644 (file)
index 0000000..c9346d1
--- /dev/null
@@ -0,0 +1,3304 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="ru" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>О %1</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>&lt;h2&gt;%1 Клиент %2&lt;/h2&gt;</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; REV %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>О программе</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>Проверить обновления</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>Не удалось открыть базу данных аккаунтов</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Авторизация истекла. Пожалуйста, войдите снова</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation>Не удалось удалить токен синхронизации локального репозитория: %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation>Не удалось получить информацию о синхронизации репозитория от сервера: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Настройки аккаунта</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Пожалуйста, введите адрес сервера</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 - неправильный адрес сервера</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Не удалось сохранить информацию об аккаунте</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Не удалось сохранить изменения: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Текущая информация об аккаунте успешно обновлена</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Адрес сервера</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Email</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ОК</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>Вы действительно хотите удалить аккаунт %1?&lt;br&gt;&lt;br&gt;Аккаунт будет удален локально. Вся конфигурация синхронизации также будет удалена. Это не повлияет на аккаунт на сервере.</translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Не удалось рассинхронизировать библиотеки этого аккаунта: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>Нажмите, чтобы открыть веб-сайт</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>Pro версия</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Нет аккаунта</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Выберите</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Настройки аккаунта</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Войти</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Удалить</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Добавить аккаунт</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Выйти</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>Вход не выполнен</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Форма</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Аккаунт</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>email</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>сервер</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>Файловая активность доступна только в %1 Server Professional Edition.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>повторить</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Не удалось получить данные об активности. Пожалуйста, %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Успешно загружено</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Файл &quot;%1&quot;
+успешно загружен.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Файл &quot;%1&quot;
+не удалось загрузить.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Ошибка доступа!</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Авторизация истекла</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Файл не существует</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation>Файл заблокирован %1, пожалуйста, попробуйте позже</translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>Ошибка загрузки: %1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Не удалось создать папку для аватаров</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>Проверка разрешения</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Задачи на скачивание</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>Удалить все успешно завершенные задания</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Сейчас нет задач на скачивание</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Очистить</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Закрыть</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Библиотека</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Путь</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Отменить это задание</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>Отменить это задание</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Удалить это задание</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Не удалось отменить задание:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Не удалось удалить задание:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Свернуть</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Закрыть</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Библиотеки</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Избранное</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Активность</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Поиск</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>Текущая скорость скачивания</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>Текущая скорость загрузки</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Выберите папку для синхронизации</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>Нет подключенных серверов</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>Все серверы подключены</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>Некоторые серверы не подключены</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Форма</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>логотип</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>Свернуть</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>Закрыть</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Выбор</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>бренд</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>или перетащите сюда папку для синхронизации</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>Скорость скачивания</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>стрелка вниз</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>Скорость загрузки</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>стрелка вверх</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Ошибка при создании конфигурации ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Невозможно создать папку предварительной настройки &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>Не удалось прочитать %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Создать библиотеку</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Выберите папку</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Создание...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Не удалось создать ключ шифрования для этой библиотеки</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Выберите папку для синхронизации</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Папка %1 не существует</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Введите имя</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Введите пароль</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Пароли не совпадают</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Неизвестная ошибка</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Не удалось добавить задачу на скачивание: 
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Не удалось создать библиотеку на сервере:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Путь:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Выберите</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Имя:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>зашифровано</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Пароль:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Пароль повторно:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>текст статуса</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ОК</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>%1 клиент не удалось инициализировать</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>%1 неожиданно вышел</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Введите пароль</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Синхронизация библиотеки &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Синхронизация папки &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Синхронизировать с папкой:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>или</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>синхронизировать с существующей папкой</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>создать новую папку для синхронизации</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Синхронизировать с этой существующей папкой:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Пожалуйста, выберите папку</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>Папка не существует</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Пожалуйста, выберите папку для синхронизации.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Ваша организация отключила вставку в библиотеку за пределы папки %1.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Конфликтует с существующим файлом &quot;%1&quot;, выберите другую папку.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Конфликтует с существующей библиотекой &quot;%1&quot;, выберите другую папку.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>Папка &quot;%1&quot; уже существует. Действительно синхронизировать с ней (содержимое будет объединено)?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Нажмите Нет для синхронизации с новой папкой вместо этого</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Невозможно найти другое имя папки</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Не удалось добавить задачу на скачивание:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Не удалось получить информацию о репозитории для скачивания
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Скачать библиотеку</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>выберите...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Пароль для этой библиотеки:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ОК</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Подробности изменения</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Добавленные файлы</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Удаленные файлы</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Измененные файлы</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Добавленные файлы</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Удаленные папки</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Открыть</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Открыть &amp;родительскую папку</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Файловый менеджер</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Назад</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>Вперед</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Домой</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Загрузить файлы</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Загрузить папку</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>У вас нет доступа для загрузки файлов в эту библиотеку</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Создать папку</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>Обновить</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 элементов</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Имя папки</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Неправильное имя папки!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>Имя &quot;%1&quot; уже занято.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>повторить</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Не удалось получить информацию о файлах.&lt;br/&gt;Пожалуйста, %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>Эта папка пуста.</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Введите имя файла, чтобы сохранить в...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>Невозможно удалить файл &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Введите путь к папке, в которую хотите сохранить...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>Действительно перезаписать существующий файл &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>Файл &quot;%1&quot; не был синхронизирован</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Файл %1 уже существует.&lt;br/&gt;Хотите перезаписать его?&lt;br/&gt;&lt;small&gt;(Выберите Нет, чтобы загрузить файл под другим именем).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>Файл не существует</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Не удалось скачать файл: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Выберите файл для загрузки</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Выберите папку для загрузки</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Переименовать</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Вы точно хотите удалить эти элементы</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Не удалось создать папку</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>Не удалось заблокировать</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Выберите файл для обновления %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Не удалось переименовать</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Не удалось удалить</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Не удалось предоставить доступ</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Нельзя вставить файлы в ту же папку</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>Нельзя вставить папку в свою подпапку</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Не удалось скопировать</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Не удалось переместить</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Не удалось создать библиотеку!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>У вас нет доступа для загрузки в эту папку</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Авторизация истекла</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Ошибка доступа!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Библиотека/Папка не найдена.</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation>Не удалось загрузить файл %1: %2</translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation>Невозможно создать папку кэша</translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation>Невозможно открыть папку кэша</translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>Поиск файлов</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Не удалось получить ссылку</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>Ожидаем</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Загрузить</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Загрузка %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>Скачать</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>Скачивание %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 из %2</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>Не удалось загрузить файл &quot;%1&quot;, повторить попытку?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>Повторить</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Пропустить</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Отменить</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>Сохранение</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>Не удалось сохранить файл</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation>Ошибка запроса прогресса индекса %1</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>Имя</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Размер</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Последнее изменение</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Показать в папке</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Показать в папке</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>Операция отменена</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>ожидаем</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>задача отменена</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Внутренняя ошибка сервера</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Квота хранения была израсходована</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>заблокировано %1</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>Имя</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Размер</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>Последнее изменение</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation>Модификатор</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Сохранить как...</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>Заблокировать</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Переименовать</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Удалить</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>Поделиться с группой</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Обновить</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Копировать</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>Выре&amp;зать</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>Вставит&amp;ь</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>От&amp;менить скачивание</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Синхронизировать эту папку</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Эта функция доступна только в Pro версии
+</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>&amp;Создать ссылку общего доступа</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>Поделиться с пользователем</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>Создать %1 внутреннюю ссылку</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Сохранить как...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>Разблокировать</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Невозможно удалить файлы только для чтения</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Невозможно вырезать файлы только для чтения</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>Повторить загрузку</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>Удалить локальную версию</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>Сохранить локальную версию как...</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation>Открыть локальную папку кэша</translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation>Не удалось получить ссылку</translation>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Не удалось создать папки</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Не удалось создать временные файлы</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Не удалось записать файл на диск</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>Не удалось удалить предыдущую версию скачанного файла</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Не удалось переместить файл</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 инициализация</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>Выберите %1 папку</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Выберите папку</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Инициализация не закончена. Действительно выйти?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Папка %1 не существует</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>заставка</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>Выберите папку</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>Выберите папку. В ней будет создана подпапка %1. Скачанные библиотеки будут сохранены там по умолчанию.</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Выберите...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Дальше</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1 хранит файлы в библиотеках.
+Хотите скачать библиотеку по умолчанию?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Проверка вашей библиотеки по умолчанию</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Создание библиотеки по умолчанию...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Не удалось создать библиотеку по умолчанию:
+
+Для выполнения данной операции версия сервера должна быть 2.1 или выше.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Не удалось получить библиотеку по умолчанию:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Не удалось создать библиотеку по умолчанию.
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Скачивание библиотеки по умолчанию...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Не удалось скачать библиотеку по умолчанию:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Скачивание библиотеки по умолчанию завершено.
+Для ее просмотра можете нажать кнопку &quot;Открыть&quot;.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Ошибка при скачивании библиотеки по умолчанию: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Не удалось скачать библиотеку по умолчанию:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1 хранит файлы в библиотеках. 
+Хотите скачать библиотеку по умолчанию?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Пропустить</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Выполнять как фоновую задачу</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Открыть</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Конец</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Скачать библиотеку по умолчанию</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Да</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>заставка</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>загрузить еще</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>Не удалось загрузить лог файлы</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Загрузка лог файлов</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>Ошибка доступа!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>Библиотека/Папка не найдена.</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>Авторизация истекла</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>Не удалось загрузить лог файлы :%1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>Лог файлы успешно загружены</translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>Сжатие</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 из %2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Добавить аккаунт</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>Единая точка входа</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>Войти заново</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Авторизуемся...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Сетевая ошибка:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Внимание:&lt;/b&gt; SSL-сертификат этого сервера не является доверенным. Продолжить несмотря на это?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Введите адрес сервера</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 неправильный адрес сервера</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Введите имя пользователя</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Пожалуйста, введите имя компьютера</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Не удалось сохранить текущий аккаунт</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1 Адрес сервера</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>Адрес сервера не должен быть пустым.</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1 неправильный адрес сервера. Должен начинаться на &apos;https://&apos;</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Введите пароль</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Неверный email или пароль</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Слишком частые попытки входа. Пожалуйста, подождите минуту</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Внутренняя ошибка сервера</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Не удалось авторизоваться: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Не удалось авторизоваться</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>заставка</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Сервер:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Например: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>или http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Пароль:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>текст статуса</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Имя компьютера: </translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>Email / Имя пользователя:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>Например, Ноутбук Ивана</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Логин</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>Автоматический вход</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Вы вышли. Пожалуйста, </translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>логин</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Добавить аккаунт</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Обновить</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation>&quot;%1&quot; не синхронизирован. 
+Причина: Удалено на сервере</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation>%1 синхронизирован</translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation>Файлы загружены в &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation>Файл %1 конфликтует</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation>Не удалось синхронизировать файл %1
+Файл заблокирован другим приложением. Этот файл будет обновлен после закрытия приложения.</translation>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation>Не удалось синхронизировать папку %1
+Какой-то файл в этот папке заблокирован другим приложением. Эта папка будет обновлена после закрытия приложения.</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation>Не удалось синхронизировать файл %1
+Файл заблокирован другим пользователем. Обновление для этого файла не загружено.</translation>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation>Не удалось проиндексировать файл %1
+Пожалуйста, проверьте разрешения файла и дисковое пространство.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation>Не удалось синхронизировать %1
+Путь к файлу заканчивается пробелом или точкой и не может быть создан в Windows.</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation>Не удалось синхронизировать %1
+Путь к файлу содержит недопустимые символы. Это не синхронизировано с этим компьютером.</translation>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation>Обновление файла %1 запрещено настройками разрешений папки.</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation>&quot;%1&quot; не удалось синхронизировать. 
+Доступ к сервису запрещен</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation>&quot;%1&quot; не удалось синхронизировать.
+Квота объёма хранилища владельца библиотеки израсходована.</translation>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>Поделиться %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>Введите имя группы</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>Введите имя пользователя или email адрес</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>Успешно обновлено</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>Не удалось предоставить общий доступ: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>Успешно удалено</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>Не удалось получить информацию об общей папке</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>Не удалось получить информацию о ваших группах и контактах</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Введите имя пользователя</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>Введите имя группы</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>Нет такой группы &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>Уже поделились с группой %1</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>Уже поделились с пользователем %1</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Предыдущая операция все еще выполняется</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>Поделиться с:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>Поделиться</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>Разрешение:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>Чтение-Запись</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>Только для чтения</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Закрыть</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>Синхронизировано</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>индексация файлов</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>инициализация синхронизации</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>Скачивание</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>Загрузка</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>синхронизация</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>ожидание синхронизации</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>Сервер не подключен</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>идентификация сервера</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>автоматическая синхронизация отключена</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>Неизвестно</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Сервер был удален</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Вы не авторизованы на сервере</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>У вас нет доступа к этой библиотеке</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Владельцем библиотеки израсходована выделенная квота</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Удаленная служба не доступна</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Доступ запрещен</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>Внутренние данные повреждены</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Не удалось запустить загрузку</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>Не удалось запустить скачивание</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Библиотека повреждена на сервере</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Конфликт при слиянии</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Версия сервера устарела</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Неизвестная ошибка</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>Ошибка сети</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>Не удалось определить адрес прокси-сервера</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>Не удалось определить адрес сервера</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>Не удалось соединиться с сервером</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>Не удалось установить безопасное соединение. Пожалуйста, проверьте SSL сертификат сервера</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation>Передача данных была прервана. Пожалуйста, проверьте сеть или брандмауэр</translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation>Передача данных прервана по тайм-ауту. Пожалуйста, проверьте сеть или брандмауэр</translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation>Неправильное HTTP перенаправление сервера. Пожалуйста, проверьте конфигурацию сервера</translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>Ошибка сервера</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>Неверный запрос</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>Недостаточно памяти</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation>Не удалось записать данные о клиенте. Пожалуйста, проверьте дисковое пространство или разрешения для папки</translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>Квота хранения заполнена</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>Библиотека удалена на сервере</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>Библиотека повреждена на сервере</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Квота хранения была израсходована</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Внутренняя ошибка сервера</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Ваш %1 клиент устарел</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Не удалось синхронизировать эту библиотеку</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Файлы заблокированы другим приложением</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Библиотека удалена на сервере</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Ошибка при доступе к локальной папке</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>Инициализация...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>Не удалось проиндексировать локальные файлы</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>Не удалось проверить информацию о сервере</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>Не удалось создать локальные файлы</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>Не удалось объединить локальные изменения файлов</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>Неверный пароль. Пожалуйста, попробуйте снова</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>Внутренняя ошибка</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>соединение с сервером...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>индексация файлов...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>Скачивание списка файлов...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>Скачивание файлов...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Создание папки...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Слияние изменения файлов ...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Готово</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>проверка информации о сервере...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Отменяется</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Отменено</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>Ошибка SSL</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Сетевая ошибка: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Ошибка сервера</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>Не удалось открыть базу сертификатов</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>Файл &quot;%1&quot; не существует в &quot;%2&quot;</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 не смог найти приложение для открытия файла %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>Создана библиотека &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>Удалена библиотека &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>Переименовать %1 в</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>Невозможно скачать элемент &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>Не удалось скопировать</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Добавлен</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Удален</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Удален</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Изменен</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Переименован</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Добавлено или изменено</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Перемещен</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Добавлена папка</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Удалена папка</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Переименованная папка</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Папка перемещена</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>файлы</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>папки</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>и еще %1</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Библиотека возвращена к статусу от</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>Файл &quot;%1&quot; возвращен к статусу от %2.</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Удаленная папка восстановлена</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Изменено имя или описание библиотеки</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>Авто слияние с %1 системой</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Только что</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1 день назад</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 день назад</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1 час назад</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 часов назад</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1 минуту назад</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 минуту назад</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Не часть сертификата&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>&gt;Синхронизировать эту библиотеку с:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Синхронизировать эту папку с:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Папка</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Папка только для чтения</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Документ</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF документ</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>Изображение</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Текстовый документ</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Аудио файл</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Видео файл</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Word документ</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>PowerPoint документ</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Excel документ</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>Путь &quot;%1&quot; конфликтует с системным путем</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>Путь &quot;%1&quot; конфликтует с существующей библиотекой</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>загрузка списка файлов</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>Файл заблокирован другим приложением</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>Папка заблокирована другим приложением</translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>Файл заблокирован другим пользователем</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>Путь неверный</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>Ошибка при индексации</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>Путь заканчивается пробелом или точкой</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>Путь содержит недопустимые символы, такие как &apos;|&apos; или &apos;:&apos;</translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation>Не удалось открыть базу данных кэша</translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation>Имя библиотеки содержит недопустимые символы, такие как &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation>Обновление файла запрещено настройками разрешений папки</translation>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation>%1 клиент уже запущен</translation>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation>Ошибка при загрузке</translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation>Ошибка при скачивании</translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation>Доступ запрещен на сервере. Пожалуйста, попробуйте повторно синхронизировать библиотеку</translation>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation>Внутренние данные повреждены на клиенте. Пожалуйста, попробуйте повторно синхронизировать библиотеку</translation>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation>Нет разрешения на запись в библиотеку</translation>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation>Нет разрешения на синхронизацию библиотеки</translation>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation>Нет разрешения на синхронизацию этой папки</translation>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation>Удалены все объекты из корзины</translation>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation>Удалены объекты старше %1 дней из корзины</translation>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation>Черновик опубликован</translation>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation>Черновик создан</translation>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation>Файл создан</translation>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation>Файл переименован</translation>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation>Черновик удален</translation>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation>Файл удален</translation>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation>Файл восстановлен</translation>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation>Файл перемещен</translation>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation>Файл обновлен</translation>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation>Папка создана</translation>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation>Папка переименована</translation>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation>Папка удалена</translation>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation>Папка восстановлена</translation>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation>Папка перемещена</translation>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation>Библиотека создана</translation>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation>Библиотека переименована</translation>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation>Библиотека удалена</translation>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation>Библиотека восстановлена</translation>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>Файл не существует</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Библиотека &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Эта библиотека еще не скачивалась</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Ошибка: </translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>каждые %1 сек.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Значок репозитория</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>Имя репозитория</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Метка</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Владелец:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Последнее изменение:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>Время изменения</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Размер:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Локальный путь:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Статус:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Статус репозитория</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Имя:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>Интервал синхронизации:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Закрыть</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Эта библиотека не может быть скачана</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>Невозможно открыть файл &quot;%1&quot; из несуществующей библиотеки &quot;%2&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Последние обновления</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Мои библиотеки</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Суб-библиотеки</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>Поделились со мной</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>Поделились со всеми</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>Поделились с группами</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Синхронизированные библиотеки</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>инициализация синхронизации</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Отключить автоматическую синхронизацию</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Включить автоматическую синхронизацию</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Показать &amp;подробности</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Показать подробности о библиотеке</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Синхронизировать эту библиотеку</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Синхронизировать эту библиотеку</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Недавно обновленные</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Синхронизировать &amp;сейчас</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Синхронизировать эту библиотеку немедленно</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>От&amp;мена скачивания</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Отмена скачивания этой библиотеки</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Открыть папку</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>открыть локальную папку</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>&amp;Открыть локальную папку</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Рассинхронизировать</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>Рассинхронизировать эту библиотеку</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Открыть в браузере</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>Открыть эту библиотеку в браузере</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>Поделиться с пользователем</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>Поделиться этой библиотекой с пользователем</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>Поделиться с группой</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>Поделиться этой библиотекой с группой</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Открыть встроенный файловый менеджер</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>открыть эту библиотеку во встроенном файловом менеджере</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>&amp;Покинуть общий доступ</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>оставить общий доступ</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>Рес&amp;инхронизировать эту библиотеку</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>Рассинхронизировать и ресинхронизировать эту библиотеку</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>Установить интервал синхронизации</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation>Установить интервал синхронизации для этой библиотеки</translation>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation>Вы уверены, что хотите рассинхронизировать библиотеку &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation>Вы уверены, что хотите пересинхронизировать библиотеку &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation>Вы уверены, что хотите перезаписать файл &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Не удалось рассинхронизировать библиотеку &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation>Вы уверены, что хотите оставить общий доступ &quot;%1&quot;?</translation>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation>Не удалось оставить общий доступ</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Не удалось отменить эту задачу: %1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Скачивание было отменено</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>У вас нет доступа для загрузки в эту папку</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>Невозможно перезаписать файл &quot;%1&quot; с самим собой</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>Не удалось удалить файл &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Не удалось загрузить файл: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>Интервал синхронизации (в секундах):</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>Установить интервал синхронизации для библиотеки &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>Поиск библиотек</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>повторить</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Не удалось получить информацию о библиотеках.&lt;br/&gt;Пожалуйста, %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Внимание:&lt;/b&gt; SSL-сертификат этого сервера не является доверенным, в любом случае продолжить?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>не удалось добавить аккаунт по умолчанию</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Ошибка инициализации лога: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Да</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Нет</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation>не удалось сохранить идентификатор клиента</translation>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation>не удалось получить доступ к %1</translation>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation>неверный идентификатор клиента</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>не удалось прочитать %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>%1 Внутренняя ссылка</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Копировать в буфер обмена</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ОК</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation>%1 Внутренняя ссылка:</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Неизвестная ошибка</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation>внутренняя ошибка: не удалось подключиться к демону</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Отключить автоматическую синхронизацию</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Включить автоматическую синхронизацию</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Выход</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Показать главное окно</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Настройки</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Открыть &amp;папку %1</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>открыть папку %1</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>Открыть папку с &amp;логами</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>Показать ошибки синхронизации файлов</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>О &amp;программе</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Показать окно About</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Онлайн справка</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Файл</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>автоматическая синхронизация отключена</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Загрузка</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>Скачивание</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>открыть папку %1 с логами</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>открыть %1 онлайн справку</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>Некоторые серверы не подключены</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>Загрузка лог файлов</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>загрузка %1 лог файлов</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>Пожалуйста, сначала войдите</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation>Исправить расширение проводник</translation>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation>Успешно исправлены значки состояния синхронизации для проводника</translation>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation>Не удалось исправить значки состояния синхронизации для проводника</translation>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>&amp;Показать в папке</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>Показать в папке</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>Поиск файлов</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>повторить</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>Не удалось найти&lt;br/&gt;Пожалуйста %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Статус соединения серверов</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>подключено</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>отключено</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Закрыть</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Пожалуйста, укажите пароль к библиотеке</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>Укажите пароль для библиотеки %1</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Пожалуйста, введите пароль</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Неверный пароль</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Неизвестная ошибка</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ОК</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Настройки</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>Автоматически запускать %1 после входа в систему</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>Спрятать иконку %1 из трея</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Нет</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP прокси</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5 прокси</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>Системный прокси</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Вы изменили язык. Перезапустить приложение сейчас?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>Хост прокси не может быть пустым</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>Порт прокси неправильный</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>Имя пользователя прокси не может быть пустым</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>Пароль прокси не может быть пустым</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Скрыть главное окно при запуске приложения</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Уведомить о синхронизации библиотек</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>Синхронизировать временные файлы MSOffice/Libreoffice</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Ограничение скорости скачивания (КБ/с):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Ограничение скорости загрузки (КБ/с):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Основной</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Не рассинхронизировать библиотеку автоматически</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Не рассинхронизировать библиотеку автоматически, когда локальная папка была удалена или стала недоступна по другим причинам.</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Не рассинхронизировать библиотеку, когда она не была найдена на сервере</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Не рассинхронизировать библиотеку автоматически, когда она не была найдена на сервере</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>Включить расширение FinderSync</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Включить расширение проводник</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>Автоматическая проверка обновлений</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>Не проверять сертификат сервера при HTTPS синхронизации</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Включить синхронизацию для папки с другим именем</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Дополнительно</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Язык (необходим перезапуск)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Язык</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Тип прокси:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Хост:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Порт:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Имя пользователя:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Пароль:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Прокси сервер требует пароль</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Сеть</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ОК</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>Чтение Запись</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Только для чтения</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>Удалить общий доступ</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>Нажмите, чтобы изменить</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>Создано %1</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>Чтение Запись</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>Только для чтения</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>Группа</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>Пользователь</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>Разрешение</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>Предыдущая операция все еще выполняется</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Ссылка</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Ссылка:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Прямое скачивание</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Копировать в буфер обмена</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ОК</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Недоверенное соединение</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 использует недействительный сертификат безопасности. Соединение может быть небезопасным. Вы желаете продолжить?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Текущий отпечаток RSA %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Предыдущий отпечаток RSA %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Запомнить мой выбор</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Да</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Нет</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Открыть</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Открыть этот файл</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>Посмотреть на &amp;веб-сайте</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>Посмотреть этот файл на веб-сайте</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>повторить</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Не удалось получить информацию об избранных файлах.&lt;br/&gt;Пожалуйста, %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>У вас еще нет избранных файлов.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>Ошибки синхронизации файлов</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>Нет ошибок синхронизации.</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>Дважды щелкните, чтобы открыть библиотеку</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>Библиотека</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Путь</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Ошибка</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>Время</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation>Введите токен двухфакторной аутентификации</translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation>Двухфакторная аутентификация</translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation>Пожалуйста, введите токен двухфакторной аутентификации</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mText</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>Запомнить это устройство</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Отмена</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>ОК</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Деинсталляция %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Желаете удалить информацию об аккаунте %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Удаление информации об аккаунте...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Диалог</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>текст</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Да</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Нет</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_sk_SK.ts b/i18n/seafile_sk_SK.ts
new file mode 100644 (file)
index 0000000..4ad569d
--- /dev/null
@@ -0,0 +1,3287 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="sk_SK" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>nepodarilo sa otvoriť databázu s účtami</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Úlohy na stiahnutie</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>zmazať všetky úspešné úlohy</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Momentálne nie sú žiadne úlohy na stiahnutie. </translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialóg</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Vyčistiť</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zavrieť</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Knižnica</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Cesta</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Zrušiť túto úlohu</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>zrušiť túto úlohu</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Odobrať túto úlohu</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Nepodarilo sa zrušiť úlohu:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Nepodarilo sa odobrať úlohu:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimalizovať</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zavrieť</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>aktuálna rýchlosť sťahovania</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>aktuálna rýchlosť nahrávania</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Prosím vyberta adresár pre synchronizáciu</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>nie je pripojený žiadny server</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>všetky servery sú pripojené</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>niektoré servery nie sú pripojené</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Formulár</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>minimalizovať</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>zatvoriť</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Vybrať</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>alebo vyberte adresár, ktorý chcete synchronizovať</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>rýchlosť sťahovania</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>šípka dole</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>rýchlosť nahrávania</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>šípka hore</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Chyba pri vytvárani ccnet konfigurácie</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>nepodarilo sa prečítať %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Vytvoriť knižnicu</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Prosím vyberte adresár</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Vytváram...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Prosím vyberte adresár na synchronizáciu</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Adresár %1 neexistuje</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Prosím vložte meno</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Prosím vložte heslo</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Heslá nie sú rovnaké</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Neznáma chyba</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Nepodarilo sa pridať úlohu na stiahnutie:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialóg</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Cesta:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Vyber</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Meno:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>zašifrovaná</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Heslo:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Heslo znova:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>text stavu</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušiť</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Prosím vložte heslo</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Synchronizovať knižnicu &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Nepodarilo sa pridať úlohu na stiahnutie:
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Stiahnuť knižnicu</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>vyber...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Heslo pre túto knižnicu:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušiť</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 Inicializácia</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Prosím vyberte adresár</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Inicializácia nie je ukončená. Naozaj odísť?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Adresár %1 neexistuje</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialóg</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Vyber...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Ďaľší</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušiť</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Kontrolujem predvolenú knižicu</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Vytváram predvolenú knižnicu...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Nepodarilo sa vytvoriť predvolenú knižnicu
+
+Server musí byť verzie 2.1 alebo vyššie pre túto funkcionalitu.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Sťahujem predvolenú knižnicu...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Predvolená knižnica bola stiahnutá.
+Pre zobrazenie môžete kliknúť na tlačítko &quot;Otvoriť&quot;.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Chyba pri sťahovaní predvolenej knižnice: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Nepodarilo sa stiahnuť predvolenú knižnicu:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialógové okno</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Preskočiť</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Bežať na pozadí</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Otvoriť</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Koniec</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Stiahnutie predvolenej knižnice</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Áno</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Pridať účet</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Prihlasujem...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Sieťová chyba:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Upozornenie:&lt;/b&gt; SSL certifikát servera nie ne dôveryhodný, pokračovať?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Prosím zadajte adresu servera</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 nie je platná adresa servera</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Prosím zadajte užívateľské meno</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Nepodarilo sa uložiť aktuálny účet</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Prosím zadajte heslo</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Neplatná mailová adresa alebo heslo</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Interná chyba na servery</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Nepodarilo sa prihlásiť: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Nepodarilo sa prihlásiť</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialóg</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Heslo:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>text stavu</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Prihlásiť</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušiť</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Obnoviť</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>zosynchronizované</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>indexujem súbory</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>inicializácia synchronizácie</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>sťahujem</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>nahrávam</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>spájam synchronizáciu</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>čakám na synchronizáciu</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>server nie je pripojený</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>overujem server</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>automatická synchronizácia je vypnutá</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>neznáme</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Server bol odobratý</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Nie ste prihlásený na serveri</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Nemáte oprávenenie na prístup k tejto knižnici</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Diskový priestor vlastníka knižnice je zaplnený</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Vzdialená služba nie je dostupná</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Knižnica je na servery zmazaná.</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>inicializácia...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>pripájanie na server...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>indexujem súbory...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Vytváram adresár...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Spájam zmeny súborov...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Ukončené</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Ruším</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Zrušené</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Knižnica &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Táto knižnica ešte nebola stiahnutá</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Chyba:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialóg</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>RepoIcon</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>RepoName</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>TextLabel</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Vlastník:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Naposledy zmenené:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Veľkosť:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Lokálna cesta:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Stav:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>RepoStatus</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Meno:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zatvoriť</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Táto knižnica nebola stiahnutá</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Nedávno aktualizované</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Moje Knižnice</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Vnorené knižnice</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Vypnúť automatickú synchronizáciu</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Zapnúť automatickú synchronizáciu</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Túto knižnicu synchronizovať okamžite</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Prerušiť sťahovanie</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Prerušiť preberanie tejto knižnice</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Otvor priečinok</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>otvor lokálny priečinok</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Odsynchronizavať</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>odsynchronizovať túto knižnicu</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Pozri v cloude</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>pozri túto knižnicu v seahube</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Nepodarilo sa odsynchronizovať knižnicu &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Nepodarilo sa zrušiť úlohu:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Preberanie bolo zrušené</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Neznáma chyba</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Vypnúť automatickú synchronizáciu</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Zapnúť automatickú synchronizáciu</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Ukončiť</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Zobraziť hlavné okno</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Nastavenia</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;O aplikácii</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Zobraziť dialóg O aplikácii</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Online pomoc</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>automatická synchronizácia je vypnutá</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>niektoré servery nie sú pripojené</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Stav pripojenia serverov</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>pripojený</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>odpojený</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialóg</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Zavrieť</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Nastavenia</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialóg</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Po spustení skryť hlavné okno</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Upozorniť keď sú knižnice synchronizované</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Limit rýchlosti sťahovania (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Limit rýchlosti nahrávania (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>0</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Zrušiť</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Odinštalovať %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Chcete odstrániť informácie o účte %1?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Odstraňujem informácie o účte...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialóg</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>text</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Áno</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nie</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_sv.ts b/i18n/seafile_sv.ts
new file mode 100644 (file)
index 0000000..194216a
--- /dev/null
@@ -0,0 +1,3274 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="sv" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>kunde inte öppna kontodatabas</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Behörighet har löpt ut, logga in igen</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Kontoinställningar</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Ange serveradressen</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 är inte en giltig serveradress</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Det gick inte att spara kontoinformation</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Det gick inte att spara ändringarna: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Uppdaterade aktuell kontoinformation</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Serveradress</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>E-postadress</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Avbryt</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>klicka för att öppna webbsidan</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>pro-version</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Inget konto</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Välj</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Kontoinställningar</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Logga in</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Ta bort</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Lägg till konto</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Logga ut</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>inte inloggad</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>e-postadress</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>server</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>ingen server ansluten</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>alla servrar anslutna</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>vissa servrar inte anslutna</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>stäng</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Välj</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>brand</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>eller släpp mapp för att synkronisera</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>nedladdningshastighet</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>uppladdningshastighet</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Kunde inte skapa ccnet-konfiguration</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>kunde inte läsa %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Skapa en katalog</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Välj en katalog</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Skapar...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>Kunde inte skapa en krypteringsnyckel för den här katalogen</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Okänt fel</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Avbryt</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Lägg till konto</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Uppdatera</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>0</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>text</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Nej</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_tr.ts b/i18n/seafile_tr.ts
new file mode 100644 (file)
index 0000000..d188dbe
--- /dev/null
@@ -0,0 +1,3295 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="tr" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>hesap veritabanı açılamadı</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>Yetkilendirme süresi doldu, lütfen yeniden giriş yapın.</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>Hesap Ayarları</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Lütfen sunucu adresini girin</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 geçerli bir sunucu adresi değil</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>Hesap bilgileri kaydedilemedi</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>Değişiklikler kaydedilemedi: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>Mevcut hesap bilgileri başarıyla güncellendi</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>Sunucu Adresi</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>Eposta</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Tamam</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>İptal et</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>Hesaba ait kütüphanelerin senkronizasyonu durdurulamadı: %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>websitesini açmak için tıklayın</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>pro versiyon</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>Hesap yok</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Seç</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>Hesap ayarları</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Giriş yap</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Sil</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Bir hesap ekleyin</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>Çıkış yap</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>giriş yapılmadı</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Form</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>Hesap</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>eposta</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>sunucu</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>tekrar dene</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>Etkinlikler bilgisi alınamadı. Lütfen %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>Yükleme başarılı</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>Dosya &quot;%1&quot;
+başarıyla yüklendi.</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>Dosya &quot;%1&quot;
+yüklenemedi.</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>Avatar klasörü oluşturma başarısız</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>İndirme görevleri</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>tüm başarılı görevleri kaldır</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Şu anda indirme görevi yok.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Temizle</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Kapat</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Kütüphane</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Yol</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Bu görevi iptal et</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>bu görevi iptal et</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Bu görevi kaldır</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Bu görev iptal edilemedi:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Bu görev kaldırılamadı:
+
+ %1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Küçült</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Kapat</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>Kütüphaneler</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>Yıldızlı</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>Etkinlikler</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>Ara</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>güncel indirme oranı</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>güncel yükleme oranı</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Lütfen senkronize etmek için bir klasör seçiniz</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>bağlı sunucu yok</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>tüm sunucular bağlı</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>bazı sunucular bağlı değil</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Form</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>küçült</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>kapat</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Seç</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>ya da Sürükle</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>indirme oranı</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>aşağı ok</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>yükleme oranı</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>yukarı ok</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>ccnet konfigürasyonu oluşturulurken hata </translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>Ön yapılandırma dizini &quot;%1&quot; oluşturulamıyor
+</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>okuma başarısız %1 </translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Bir kütüphane oluştur</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Lütfen bir dizin seçin</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Oluşturuyor...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Lütfen senkronize edilecek dizini seçin</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Klasör %1 yok</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Lütfen isim giriniz</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Lütfen şifreyi giriniz</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Şifreler eşleşmiyor</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Bilinmeyen hata</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>İndirme görevi ekleme başarısız:
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>Sunucuda kütüphane oluşturma başarısız:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Yol:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Seç</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>İsim:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>şifreli</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Şifre:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Şifre Tekrar:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>durum metni</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Tamam</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>İptal et</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Lütfen şifreyi girin</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Kütüphaneyi Senkronize et &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>Senkronizasyon klasörü &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>Klasöre senkronize et:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>ya da</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>mevcut bir klasörle senkronize et</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>yeni bir senkronizasyon klasörü oluştur</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>Bu mevcut klasörle senkronize et:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>Lütfen bir klasör seçin</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>Klasör mevcut değil</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>Lütfen senkronize edilecek klasörü seçin.</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>Organizasyonunuz %1 klasörü dışına kütüphane koyulmasını engelliyor.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Mevcut &quot;%1&quot; dosyası ile uyuşmazlık var, lütfen başka bir klasör seçin.</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>Mevcut &quot;%1&quot; kütüphanesi ile uyuşmazlık var, lütfen başka bir klasör seçin.</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>&quot;%1&quot; klasörü zaten var. Onunla senkronize etmek istediğinize emin misiniz (içerikler birleştirilecek)?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>Yeni bir klasörle senkronize etmek için Hayır&apos;ı tıklayın</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>Alternatif bir klasör ismi bulunamıyor</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>İndirme görevi ekleme başarısız:
+ %1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>Repo indirme bilgisi alınamadı:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Kütüphaneyi İndir</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>seç...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Bu kütüphane için şifre:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Tamam</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>İptal Et</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>Değiştirme Ayrıntıları</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>Eklenen dosyalar</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>Silinen dosyalar</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>Değiştirilen dosyalar</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>Eklenen klasörler</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>Silinen klasörler</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Aç</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>Aç &amp;ebeveyn klasör</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>Bulut Dosya Tarayıcısı</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>Geri</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>İlet</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Anasayfa</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>Dosyaları yükle</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>Bir dizin yükle</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>Bu kütüphaneye dosya yüklemek için izniniz yok</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>Bir klasör oluşturun</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>Klasör adı </translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>Geçersiz klasör adı!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>&quot;%1&quot; ismi daha önce alınmış.</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>tekrar deneyin</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>Dosya bilgileri alınamadı&lt;br/&gt;Lütfen %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>Kaydetmek için dosya adını girin</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; dosyası kaldırılamıyor</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>Kaydetmek istediğiniz klasör yolunu girin...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>&quot;%1&quot; dosyasının üzerine yazmak istiyor musunuz?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>&quot;%1&quot; dosyası senkronize edilmedi</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>Dosya %1 zaten var.&lt;br/&gt;Üstüne yazmak ister misiniz?&lt;br/&gt;&lt;small&gt;(Başka bir isim kullanarak yüklemek için Hayır seçin).&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>Dosya indirme başarısız: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>Yüklemek için bir dosya seçin</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>Yüklemek için bir dizin seçin</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Yeniden adlandır</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>Bu öğeleri silmeyi gerçekten istiyor musunuz?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>Klasör oluşturma başarısız</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>Güncellemek için bir dosya seç %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>Yeniden adlandırılamadı</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>Taşıma başarısız</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>Paylaşma başarısız</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>Aynı klasörden dosyalar yapıştırılamaz</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>Kopyalama başarısız</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>Taşıma başarısız</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>Kütüphane oluşturma başarısız!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>İptal et</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>Yükle</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>Yüklüyor %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>İndir</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>İndiriyor %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%2 de %1</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>İşlem iptal edildi.</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>beklemede</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>İç Sunucu Hatası</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>İsim</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>Boyut</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>En son Değiştirme</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>&amp;Farklı kaydet</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>&amp;Yeniden Adlandır</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>&amp;Sil</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>&amp;Güncelle</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>&amp;Kopyala</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>&amp;Kes</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>&amp;Yapıştır</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>&amp;İndirmeyi iptal et</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>&amp;Bu klasörü senkronize et</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>Bu özellik sadece pro versiyonda mevcut</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>&amp;Buraya farklı kaydet...</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>Salt okunur dosyalar kaldırılamıyor</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>Salt okunur dosyalar kesilemiyor</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>Klasör oluşturma başarısız</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>Geçici dosya oluşturma başarısız</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>Dosyayı diske yazma başarısız</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>İndirilen dosyanın eski versiyonu kaldırılamadı</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>Dosya kaldırılamadı</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 başlatma</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Lütfen bir dizin seçin</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Başlatma henüz bitmedi. Gerçekten çıkıyor musunuz?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Klasör %1 yok</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Seç...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Sonraki</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>İptal et</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Varsayılan kütüphanenizi kontrol ediyor...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Varsayılan kütüphane oluşturuluyor...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Varsayılan kütüphane oluşturma başarısız:
+
+Bu işlemin desteklenmesi için Sunucu versiyonu 2.1 ya da daha yüksek olmalı.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>Varsayılan kütüphaneyi alma başarısız:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>Varsayılan kütüphane oluşturma başarısız:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Varsayılan kütüphane indiriliyor...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>Varsayılan kütüphaneyi indirme başarısız:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Varsayılan kütüphane indirildi.
+Görüntülemek için &quot;Aç&quot; düğmesine basabilirsiniz.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Varsayılan kütüphane indirilirken hata oluştu: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Varsayılan kütüphaneyi indirme başarısız oldu:
+ %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Atla</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Arka planda yürüt</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Aç</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Son</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Varsayılan Kütüphaneyi İndir</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Evet</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Hesap ekle</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>yeniden giriş yapın</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Giriş yapıyor...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Ağ Hatası:
+ %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Uyarı:&lt;/b&gt; Bu sunucunun ssl sertifikası güvenilir değil, yine de devam edilsin mi?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Lütfen sunucu adresini giriniz</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 geçerli bir sunucu adresi değil</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>lütfen kullanıcı adını giriniz</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Lütfen bilgisayar adını giriniz</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Mevcut hesabı kaydetme başarısız</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Lütfen şifreyi giriniz</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Hatalı eposta ya da şifre</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>Çok sık giriş yapılıyor, lütfen bir dakika bekleyin</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>İç Sunucu Hatası</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Giriş yapılamadı: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Giriş yapılamadı</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>logo</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>Sunucu:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Örneğin: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>or http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Şifre:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>durum metini</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>Bilgisayar Adı:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>örnek: Can&apos;ın bilgisayarı</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Giriş</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>İptal et</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>Çıkış yaptınız. Lütfen</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>giriş yap</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>Hesap ekle</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Yenile</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>senkronize</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>dosyaları indeksliyor</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>senkronizasyon başlatılıyor</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>indiriyor</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>yüklüyor</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>senkronizasyon birleştirme</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>senkronizasyon için bekliyor</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>sunucu bağlı deği</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>sunucu kimliği doğrulanıyor</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>oto senkronizasyon kapatıldı</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>bilinmeyen</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Sunucu kaldırıldı</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Sunucuya giriş yapmadınız</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>Bu kütüphaneye erişim izniniz yok</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Kütüphane sahibinin depolama alanı tükendi.</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Uzaktan hizmet kullanılamıyor</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>Servise erişim reddildi</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>İç veri bozuk</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>Yükleme başlatılamadı</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>İndirme başlatılamadı</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>Kütüphane sunucuda hasar gördü</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Birleştirmede uyuşmazlık</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Sunucu versiyonu çok eski</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Bilinmeyen hata</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>Depolama kotası tükendi</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>İç sunucu hatası</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>%1 istemciniz çok eski</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Kütüphane senkronizasyonu başarısız oldu</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>Dosyalar bir başka uygulama tarafından kilitlendi</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Kütüphane sunucuda silindi</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>Lokal dosyaya erişim hatası</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>başlatılıyor...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>sunucuya bağlanıyor...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>dosyalar indeksleniyor...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Dosya oluşturuyor...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Dosya değişikliklerini birleştiriyor...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Tamam</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>İptal ediyor</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>İptal edildi</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL Hatası</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Ağ Hatası: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Sunucu Hatası</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>Veritabanı sertifikası açılamadı</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation> &quot;%2&quot;&apos;de dosya &quot;%1&quot; mevcut değil</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1  %2 dosyasını açmak için uygulama bulamadı.</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; kütüphanesini oluştur.</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; silinmiş kütüphane</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>%1&apos;i Yeniden adlandır </translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; öğesi indirilemedi</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>kopyalama başarısız</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>Eklendi</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>Silindi</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>Kaldırıldı</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>Değiştirildi</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>Yeniden adlandırıldı</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>Eklendi ya da değiştirildi</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>Taşındı</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>Eklenen dizin</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>Kaldırılan dizin</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>Yeniden adlandırılan dizin</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>Taşınan dizin</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>dosyalar</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>dizinler</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>ve %1 tane daha</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>Şu duruma geri çevrilmiş kütüphane</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>%2 durumuna çevrilmiş &quot;%1&quot; dosyası</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>Kurtarılan silinmiş kütüphane</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>Değiştirilmiş kütüphane adı ya da açıklaması</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>Hemen şimdi</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1 gün önce</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 gün önce</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1 saat önce</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 saat önce</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation> 1 dakika önce</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 dakika önce</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;Not Part of Certificate&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>Bu kütüphaneyi şuraya eşitle:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>Bu klasörü şuraya eşitle:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>Klasör</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>Salt okunur Klasör</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>Doküman</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF Dokümanı</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>İmaj dosyası</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>Text Dokümanı</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>Ses Dosyası</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>Video Dosyası</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Word Dokümanı</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>PowerPoint Dokümanı</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Excel Dokümanı</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Kütüphane &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Bu kütüphane henüz indirilmedi</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Hata:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>RepoSimgesi</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>RepoAdı</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>MetinEtiketi</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Sahip:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>En son Değiştirme:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>mtime</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Boyut:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Lokal Yol:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Durum:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>RepoDurumu</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>İsim:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Kapat</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Bu kütüphane henüz indirilmedi</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>Varolmayan &quot;%2&quot; kütüphanesinden &quot;%1&quot; dosyası açılamıyor</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Yeni Güncellenen</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Kütüphanelerim</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Alt Kütüphaneler</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>Senkronize Kütüphaneler</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Oto senkronizasyonu devre dışı bırak</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Oto senkronizasyonu etkinleştir</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>Göster &amp;ayrıntılar</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Bu kütüphanenin ayrıntılarını göster</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Bu kütüphaneyi senkronize et</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Bu kütüphaneyi senkronize et</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Yeni Güncellenen</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>Eşitle &amp;şimdi</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Bu kütüphaneyi hemen senkronize et</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;İptal et indirme</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Bu kütüphaneyi indirmeyi iptal et</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>Dosyayı &amp;Aç </translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>lokal dosya aç</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Senkronizasyonu sonlandır</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>Bu kütüphane senkronizasyonunu sonlandır</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Görüntüle Bulutta</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>bu kütüphaneyi seahub&apos;da görüntüle</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>&amp;Aç bulut dosya tarayıcısı</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>bu kütüphaneyi Bulut Dosya Tarayıcısına gömülü aç</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>Bu kütüphaneyi &amp;Yeniden Senkronize Et</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>bu kütüphanenin senkronizasyonu sonlandır ve yeniden senkronize et</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; kütüphanesinin senkronizasyonu sonlandırılamadı.</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Bu görev iptal edilemedi:
+
+ %1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>İndirme iptal edildi</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation> &quot;%1&quot; dosyası kendi üzerine yazılamıyor</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>&quot;%1&quot; dosyası silinemedi</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>Dosya yüklenemedi: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>tekrar dene</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>Kütüphane bilgisi alınamadı&lt;br/&gt;Lütfen %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Uyarı:&lt;/b&gt; Bu sunucunun ssl sertifikası güvenilir deği, yine de devam edilsin mi?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>Log %s başlatılamadı</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Panoya kopyala</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Tamam</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Bilinmeyen hata</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Oto senkronizasyonu devre dışı bırak</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Oto senkronizasyonu etkinleştir</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Çık</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Ana pencereyi göster</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Ayarlar</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>Aç &amp;dosya  %1</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>%1 dosyasını aç</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>&amp;logs klasörünü aç</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Hakkında</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Uygulamanın Hakkında kutusunu göster</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Çevrimiçi Yardım</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>Dosya</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>Oto senkronizasyon devre dışı bırakıldı</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>Yüklüyor</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>İndiriyor</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>%1 log klasörünü aç</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>%1 online yardımı aç</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>bazı sunucular bağlı değil</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Sunucunun bağlantı durumu</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>bağlı</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>bağlı değil</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Kapat</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>Lütfen kütüphane şifresini giriniz</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>%1 kütüphanesi için şifre giriniz</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Lütfen şifreyi giriniz</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>Hatalı şifre</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Bilinmeyen hata</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Tamam</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>İptal et</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Ayarlar</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>Hiç</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP Proxy</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>Socks5 Proxy</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>Dili değiştirdiniz. Uygulamak için yeniden başlatılsın mı?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Başlarken ana pencereyi gizle</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Kütüphaneler senkronize edilince bildir</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>MSOffice/Libreoffice &apos;deki geçici dosyaların senkronizasyonunu etkinleştir</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>İndirme hız limiti </translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Yükleme hız limiti (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>Temel</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>Bir kütüphaneyi senkronize etmeyi otomatik olarak durdurma</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>Bir kütüphaneyi lokal dizini kaldırıldığında ya da başka bir nedenle erişilmez olduğunda senkronize etmeyi otomatik olarak durdurma</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>Bir kütüphaneyi sunucuda bulunmadığında senkronize etmeyi durdurma</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>Bir kütüphane sunucuda bulunmadığında senkronize etmeyi otomatik olarak sonlandırma.</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>FinderSync uzantısını etkinleştir</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>Explorer uzantısını etkinleştir</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>HTTPS senkronizasyonunda sunucu sertifası doğrulamayın</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>Başka bir isimli mevcut bir dosya ile eşitlemeyi etkinleştir</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Gelişmiş</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>Dil (yeniden başlatma gerekir)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>Dil</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>Proxy Çeşidi:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Host:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Port:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>Kullanıcı adı:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Şifre:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>Proxy suucu şifre gerektirir</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>Ağ</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Tamam</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>İptal et</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>Bağlantı Paylaş</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>Bağlantı paylaş:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>Doğrudan İndirme</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>Panoya kopyala</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Tamam</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Güvenilmeyen Bağlantı</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 geçersiz bir güvenlik sertifikası kullanıyor. Bağlantı güvenilir olmayabilir. Devam etmek istiyor musunuz?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>Mevcut RSA anahtar parmakizi %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>Önceki RSA anahtar parmakizi %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Seçimimi hatırla</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Evet</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Hayır</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>&amp;Aç</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>Bu dosyayı aç</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>Web&apos;de &amp;Görüntüle</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>bu dosyayı websitesinde görüntüle</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>tekrar dene</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>Yıldızlı dosyaların bilgileri alınamadı&lt;br/&gt;Lütfen %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>Henüz yıldızlı dosyanız yok</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>%1&apos;i kaldır</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>%1 hesabının bilgilerini kaldırmak istiyor musunuz?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Hesap bilgileri kaldırılıyor...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>metin</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Evet</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Hayır</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_uk.ts b/i18n/seafile_uk.ts
new file mode 100644 (file)
index 0000000..5f4469b
--- /dev/null
@@ -0,0 +1,3287 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="uk" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>Не вдалося відкрити базу даних облікових записів</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>email</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>server</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>Завдання завантаження</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>видалити всі успішні завдання</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>Зараз немає завдань завантаження.</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Діалог</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Очистити</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Закрити</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>Бібліотека</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>Шлях</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>Скасувати це завдання</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>скасувати це завдання</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>Видалити це завдання</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Не вдалося скасувати це завдання:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>Не вдалося видалити цю задачу:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>Згорнути</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Закрити</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>поточна швидкість завантаження</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>поточна швидкість віддачі</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>Будь ласка, оберіть папку для синхронізації</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>немає підключеного серверу</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>усі сервери підключено</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>деякі сервери не підключені</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Форма</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>лого</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>згорнути</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>закрити</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Обрати</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>чи Перетягніть каталог</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>швидкість завантаження</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>стрілка вниз</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>швидкість віддачі</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>стрілка вгору</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>Помилка при створенні конфігурації ccnet</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>не вдалося прочитати %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>Створення бібліотеки</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Будь ласка, оберіть каталог</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>Створення...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>Будь ласка, оберіть каталог для синхронізації</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Каталог  %1 не існує</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>Будь ласка, введіть ім&apos;я</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Будь ласка, введіть пароль</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>Паролі не збігаються</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Невідома помилка</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Не вдалося додати завдання завантаження:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Діалог</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>Шлях:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>Вибрати</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Назва:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>зашифровано</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Пароль:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>Пароль ще раз:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>статус</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Відміна</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Будь ласка, введіть пароль</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>Синхронізація бібліотеки &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>Не вдалося додати завдання завантаження:
+%1 </translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>Завантажити бібліотеку</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>обрати...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>Пароль для цієї бібліотеки</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Скасувати</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 ініціалізація</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>Будь ласка, оберіть каталог</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>Ініціалізацію не закінчено. Дійсно вийти?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>Каталог %1 не існує</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Діалог</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>лого</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>Оберіть...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>Далі</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Скасувати</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>Перевірка Вашої бібліотеки за замовчанням...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>Створення бібліотеки за замовчанням...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>Не вдалося створити бібліотеку за замовчанням:
+
+Необхідна версія сервера 2.1 або вище для підтримки цієї функції.</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>Завантаження бібліотеки за замовчанням...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>Вашу бібліотеку за замовчанням було завантажено.
+Клікніть &quot;Відкрити&quot; щоб переглянути ії.</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>Помилка при завантаженні бібліотеки за замовчанням: %1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>Не вдалося скачати бібліотеку за замовчанням:
+ %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Діалог</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>Пропустити</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>Виконати в фоновому режимі</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>Відкрити</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>Готово</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>Скачати бібліотеку за замовчанням</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Так</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>лого</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>Додати обліковий запис</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>Вхід...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>Помилка мережі:
+ %1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;Увага:&lt;/b&gt; SSL-сертифікат цього сервера не є надійним! Продовжувати?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>Будь ласка, введіть адресу сервера</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 адреса сервера не припустима</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>Будь ласка, введіть ім&apos;я користувача</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>Будь ласка, введіть ім&apos;я комп&apos;ютера</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>Не вдалося зберігти поточний аккаунт</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>Будь ласка, введіть пароль</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>Невірні email або пароль</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>Внутрішня помилка на сервері</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>Не вдалося увійти в систему з логіном: %1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>Не вдалося увійти в систему</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Діалог</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>лого</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>Пароль:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>текст статусу</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>Логін</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Відміна</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>Оновити</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>синхронізований</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>індексація файлів</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation> ініціалізація синхронізації</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>завантаження</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>віддача</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>синхронізувати злиття</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>очікування синхронізації</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>сервер не з&apos;єднано</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>аутентифікація на сервері</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>автоматичну синхронізацію вимкнено</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>невідомий</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>Сервер був видалений</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>Ви не ввійшли до серверу</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>У вас немає дозволу на доступ до цієї бібліотеки</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>Власник бібліотеки вичерпав дозволене місце для зберігання</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>Віддалений сервіс недоступний</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>Конфлікт у злитті</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>Занадто стара версія сервера </translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>Невідома помилка</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>Внутрішня помилка сервера</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>Ваш клієнт %1 занадто старий</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>Не вдалося синхронізувати цю бібліотеку</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>Бібліотека видалена на сервері</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>Ініціалізація...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>з&apos;єднання з сервером...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>індексація файлів...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>Створення каталогу...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>Об&apos;єднання змін файлів...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>Готово</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>Скасування</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>Скасовано</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL Помилка</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>Помилка мережі: %1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>Помилка серверу</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>не вдалося відкрити базу даних сертифікатів</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>Бібліотека &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>Ця бібліотека ще не завантажена</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>Помилка:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Діалог</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>Іконка репозиторію</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>Ім&apos;я репозиторію</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>Текстова мітка</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>Власник:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>Остання зміна:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>час</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>Розмір:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>Локальний шлях:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>Статус:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>Статус</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>Назва:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Закрити</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>Цю бібліотеку не було завантажено</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>Нещодавно оновлено</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>Мої бібліотеки</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>Суб-бібліотеки</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Вимкнути автосинхронізацію</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Увімкнути автосинхронізацію</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>Показати деталі цієї бібліотеки</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>&amp;Синхронізація цієї бібліотеки</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>Синхронізація цієї бібліотеки</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>Синхронізувати цю бібліотеку негайно</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>&amp;Відмінити завантаження</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>Відмінити завантаження цієї бібліотеки</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>&amp;Відкрити каталог</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>відкрити локальний каталог</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>&amp;Розсинхронізація</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>розсинхронізувати цю бібліотеку</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>&amp;Перегляд у хмарі</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>переглянути цю бібліотеку на вебсайті</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>Не вдалося розсинхронізувати бібліотеку &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>Не вдалося скасувати це завдання:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>Завантаження було скасоване</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt; Увага: &lt;/ B&gt; SSL-сертифікат цього сервера не є надійним, в будь-якому випадку продовжити?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>Невідома помилка</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>Вимкнути автосинхронізацію</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>Увімкнути автосинхронізацію</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>&amp;Вихід</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>Показати головне вікно</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>Налаштування</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>&amp;Інфо</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>Показати інформацію про програму</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>&amp;Онлайн допомога</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>автосинхронізацію вимкнено</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>деякі сервери не підключені</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>Статус з&apos;єднання</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>з&apos;єднано</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>від&apos;єднано</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Діалог</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>Закрити</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>Налаштування</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Діалог</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>Ховати головне вікно при старті</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>Повідомляти про синхронізацію бібліотек</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>Обмеження швидкості скачування (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>Обмеження швидкості завантаження (KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>0</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Відміна</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>Ненадійне з&apos;єднання</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Діалог</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>Запам&apos;ятати мій вибір</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Так</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Ні</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>Деінсталювати %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>Дійсно хочете видалити інформацю облікового запису %1 ?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>Видалення інформації облікового запису...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>Діалог</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>текст</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>Так</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>Ні</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_zh_CN.ts b/i18n/seafile_zh_CN.ts
new file mode 100644 (file)
index 0000000..d98c67c
--- /dev/null
@@ -0,0 +1,3296 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_CN" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation>关于 %1
+</translation>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation>%1 客户端 %2</translation>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation>&lt;h5&gt; 版本 %1 &lt;/h5&gt;</translation>
+    </message>
+    <message>
+        <source>About</source>
+        <translation>关于</translation>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation>检查更新</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>确定</translation>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>打开帐户数据库失败</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>账号验证信息已过期,请重新登录</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation>删除本地资料库同步验证信息失败:%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation>从服务器上获取资料库同步信息失败:%1</translation>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>帐户设置</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>请输入云盘网址</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 不是合法的云盘网址</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>保存帐户信息失败</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>保存修改失败: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>成功更新当前帐户设置</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>云盘网址</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>邮箱</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>确定</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation>确定要删除账号 %1 吗?&lt;br&gt;&lt;br&gt;这个账号会从本地删除。同步配置也会被删除。服务器上的账号不会受到影响。</translation>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>解除同步该帐号的资料库失败:%1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>点击跳转到网页版</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>企业版</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>没有帐号</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>选择</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>帐户设置</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>登录</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>删除</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>添加一个帐号</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>登出</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>没有登录</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Form</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>帐号</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>邮箱</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>服务器</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>文件活动功能仅在 %1 企业版中提供。</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>重试</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>获取文件活动信息失败,请 %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>上传成功</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>文件 &quot;%1&quot;
+已成功上传。</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>文件 &quot;%1&quot;
+无法上传。</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>权限错误</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>账号验证信息已过期</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>文件不存在</translation>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation>该文件被 %1锁定,请稍后再试</translation>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation>上传失败:%1</translation>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>创建头像文件夹失败</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation>正在检查权限</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>下载任务</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>移除所有已完成任务</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>当前没有下载任务。</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>清除</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>关闭</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>资料库</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>路径</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>取消任务</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>取消任务</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>删除任务</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>取消任务失败:%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>删除任务失败:%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>最小化</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>关闭</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>资料库</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>星标文件</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>文件活动</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>搜索</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>当前下载速率</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>当前上传速率</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>请选择一个文件夹来同步</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>服务器连接失败</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>所有服务器已连接</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>一些服务器未连接</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>Form</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>标志</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>最小化</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>关闭</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>选择文件夹</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation>brand</translation>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>或拖拽到这里进行同步</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>下载速率</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>向下的箭头</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>上传速率</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>向上的箭头</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>创建 ccnet 配置时出错</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>无法创建预配置文件夹 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>读取文件 %1 失败</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>创建新资料库</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>请选择一个文件夹</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>正在创建...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation>生成资料库密钥时出错</translation>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>请选择要同步的文件夹</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>文件夹 %1 不存在</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>请输入资料库名称</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>请输入资料库密码</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>密码不一致</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>未知错误</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>添加下载任务失败:%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>创建资料库失败:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>路径:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>选择</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>名字:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>加密</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>密码:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>确认密码:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>状态文本</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>确定</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation>%1 客户端初始化时出错</translation>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation>%1意外退出</translation>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>请输入密码</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>同步资料库 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>同步此目录 “%1”</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>同步到目录:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>或者</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>和已有文件夹同步</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>创建一个新的文件夹用于同步</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>和这个已存在文件夹同步:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>请选择一个目录</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>文件夹不存在</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>请选择用于同步的目录</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>您的组织已禁用把资料库放在 %1 目录外</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>和已有文件 &quot;%1&quot; 冲突,请选择其他目录。</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>和已同步的资料库 &quot;%1&quot; 冲突,请选择其他目录。</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>文件夹 &quot;%1&quot; 已存在。请问您是否和它同步 (其中内容会被合并)?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>点击“否” 与一个新的文件夹同步</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>无法找到其他可用的文件夹名称</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>添加下载任务失败:%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>下载资料库信息失败:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>下载资料库</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>选择...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>该资料库的密码:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>确定</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>修改详情</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>已添加的文件</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>已删除的文件</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>已修改的文件</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>已添加的文件夹</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>已删除的文件夹</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>打开(&amp;O)</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>打开父文件夹(&amp;P)</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>云端文件浏览器</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>后退</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>前进</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>根目录</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>上传多个文件</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>上传文件夹</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>您没有权限上传到文件这个资料库</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>创建文件夹</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation>刷新</translation>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation>%1 个条目</translation>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>文件夹名称</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>无效的文件夹名!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>文件名 &quot;%1&quot; 已经被使用了。</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>重试</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>获取文件信息失败&lt;br/&gt;请 %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation>该文件夹是空的。</translation>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>请键入需要另存为的文件名...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>无法删移文件 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>请键入需要另存到的文件夹的路径...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>您真的想删除已存在的文件 &quot;%1&quot; 吗?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>文件 &quot;%1&quot; 没有被同步</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>文件 &quot;%1&quot; 已经存在。&lt;br/&gt;您想覆盖此文件吗?&lt;br/&gt;&lt;small&gt;(选择 否 用其他文件名上传)&lt;/small&gt; </translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation>文件不存在</translation>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>下载文件失败: %1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>请选择要上传的文件</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>请选择要上传的目录</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>重命名</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>您真的想删除这些文件吗?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>创建文件夹失败</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation>锁定文件失败</translation>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>请选择要需要上传的文件 以更新 %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>重命名失败</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>删除失败</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>共享失败</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>无法从相同的文件夹中拷贝</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation>不能把文件夹复制到它的子文件夹中</translation>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>复制失败</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>移动失败</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>创建资料库失败!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>您没有权限上传到这个目录</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>账号验证信息已过期</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>权限错误</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>资料库/文件夹没有发现</translation>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation>上传文件失败 %1: %2</translation>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation>不能创建缓存目录</translation>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation>不能打开缓存目录</translation>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation>搜索文件</translation>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation>获取链接失败</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation>请稍候</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>上传</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>正在上传 %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>下载</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>正在下载 %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%2 的 %1</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation>文件 “%1” 上传失败,您想要重试吗?</translation>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation>重试</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>跳过</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>中止</translation>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation>保存中</translation>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation>文件保存失败</translation>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation>索引处理请求错误 %1</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation>文件名</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>大小</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>修改时间</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>打开所在文件夹(&amp;S)</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>打开所在文件夹</translation>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>操作被取消</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>请稍后</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation>任务被取消</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>服务器内部错误</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>该用户的空间已经用完</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation>被 %1 锁定</translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>文件名</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>大小</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>修改时间</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation>修改者</translation>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>另存为...(&amp;S)</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation>锁定(&amp;L)</translation>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>重命名(&amp;R)</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>删除 (&amp;D)</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation>共享给群组</translation>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>更新 (&amp;U)</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>复制 (&amp;C)</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>剪切 (&amp;T)</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>粘贴 (&amp;P)</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>取消下载(&amp;C)</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>同步该目录(&amp;S)</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>此功能只在企业版中提供</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation>获取%1下载链接</translation>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation>共享给其他用户</translation>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation>获取%1内部链接(&amp;E)</translation>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>另存至...(&amp;S)</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation>解除锁定(&amp;l)</translation>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>无法删移只读文件</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>无法剪切只读文件</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation>重试上传</translation>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation>删除本地版本</translation>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation>本地版本另存为...</translation>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation>打开本地缓存目录</translation>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation>获取链接失败</translation>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>创建文件夹失败</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>创建临时文件失败</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>写文件失败</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>移动旧文件时出错</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>移动文件时出错</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 初始化</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation>选择 %1 文件夹</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>请选择一个文件夹</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>初始化未完成,确认退出?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>文件夹 %1 不存在</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>标志</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation>选择一个文件夹</translation>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation>请选择一个文件夹。我们会在这个文件夹下创建 %1 目录,您下载的资料库将默认保存在此处。</translation>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>选择...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>下一步</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation>%1用资料库的方式来组织文件。
+您想要下载您的默认资料库吗?</translation>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>正在获取默认资料库信息...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>正在创建默认资料库...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>创建默认资料库失败:
+服务器版本必须是 2.1 以上才支持默认资料库功能。</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>获取默认资料库失败:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>创建默认资料库失败:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>正在下载默认资料库...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>下载默认资料库失败:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>默认资料库已下载。
+您可以点击“打开”按钮来查看它。</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>下载默认资料库时出错:%1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>下载资料库 “%1” 失败</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation>%1用资料库的方式来组织文件。
+您想要下载您的默认资料库吗?</translation>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>跳过</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>后台运行</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>打开</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>完成</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>下载默认资料库</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>是</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>标志</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation>加载更多</translation>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation>上传日志文件失败</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>上传日志文件</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation>权限错误!</translation>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation>资料库/文件夹没有发现</translation>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation>账号验证信息已过期</translation>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation>上传日志文件失败 :%1</translation>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation>上传日志文件成功</translation>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation>压缩中</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>%1 的 %2</translation>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>添加帐号</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation>单点登录或微信登录</translation>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>重新登录</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>登录中...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>网络错误:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;警告:&lt;/b&gt; 该服务器的SSL 证书不可信,是否继续?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>请输入云盘网址</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 不是合法的云盘网址</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>请输入邮箱</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>请填写计算机名</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>保存帐户失败</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation>%1 云盘网址</translation>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation>服务器地址不能为空</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation>%1  不是合法的服务器地址。地址必须以 &quot;https://&quot; 开头</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>请输入密码</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>错误的邮箱或密码</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>登录过于频繁,请稍后再试</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>服务器内部错误</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>登录失败:%1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>登录失败</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>标志</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>云盘网址:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;例如: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>或者 http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>密码:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>状态文本</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>计算机名:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation>邮箱 / 用户名:</translation>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>例如:小王的工作笔记本</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>登录</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation>自动登录</translation>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>您已登出。请</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>登录</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>添加一个帐号</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>刷新</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation>“%1”未同步
+原因:在服务器上删除</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation>“%1”已同步</translation>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation>文件已经上传到 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation>文件 %1 同步时发生冲突</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation>同步文件 %1 出错
+文件被其他应用锁定。这个文件将在该应用退出时更新。</translation>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation>同步文件夹 %1 出错
+该文件夹中的某个文件被其他应用锁定。这个文件夹将在该应用退出时更新。</translation>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation>同步文件 %1 出错
+该文件被其他用户锁定,因此对它作的修改不会被上传。</translation>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation>读取 %1 内容出错
+请检查文件权限以及磁盘可用空间。</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation>同步文件 %1 出错
+该文件路径包含空格或点号,因此无法在 windows 上创建</translation>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation>同步文件 %1 出错
+该文件路径包含非法字符,因此它不会被同步到这台计算机。</translation>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation>文件夹权限设置导致文件 %1 无法被更新</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation>&quot;%1&quot; 同步出错。
+您没有权限访问该资料库</translation>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation>&quot;%1&quot; 同步出错。
+该资料库所有者的空间限额已用完。</translation>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation>路径 %1 设置了不可同步的共享权限</translation>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation>只读资料库下的文件改动不会被上传</translation>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation>共享 %1</translation>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation>输入群组名称</translation>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation>输入用户名或邮件地址</translation>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation>操作成功</translation>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation>共享操作失败: %1</translation>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation>删除共享成功</translation>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation>获取文件夹共享信息时出错</translation>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation>获取群组和联系人信息时出错</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>请输入用户名</translation>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation>请输入群组名</translation>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation>“%1” 群组不存在</translation>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation>已经共享给 “%1” 群组了</translation>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation>已经共享给用户 %1 了</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>上一个操作还未完成</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation>共享给:</translation>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation>共享</translation>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation>权限:</translation>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation>可读写</translation>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation>只读</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>关闭</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>已同步</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>索引文件</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>初始化</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>下载中</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>上传中</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>合并更改</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>等待同步</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>服务器未连接</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>服务器验证中</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>自动同步已关闭</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>未知</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>服务器已经被删除</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>您还没登录到服务器上</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>您没有权限访问这个资料库</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>资料库所有者的空间限额已用完</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>与服务器通信失败</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>没有访问权限</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>内部数据损坏</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>启动上传失败</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>启动下载失败</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>该资料库在服务器上已损坏</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>合并文件更改时产生冲突</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>服务器版本太低</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>未知错误</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation>网络错误</translation>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation>无法解析代理服务器地址</translation>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation>无法解析服务器地址</translation>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation>无法建立到服务器的连接</translation>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation>建立安全连接时出错。请检查服务器 SSL 证书</translation>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation>数据传输被中断。请检查网络或防火墙设置</translation>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation>数据传输超时。请检查网络或防火墙设置</translation>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation>不能处理服务器的 HTTP 重定向。请检查服务器配置</translation>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation>服务器内部错误</translation>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation>非法的请求</translation>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation>计算机内存不够</translation>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation>本地文件写入出错。请检查文件权限以及磁盘可用空间。</translation>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation>用户存储空间已用完</translation>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation>资料库在服务器上被删除</translation>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation>该资料库在服务器上已损坏</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>该用户的空间已经用完</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>服务器出错了</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>您的 %1 客户端版本太低</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>同步该资料库时出错</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>文件已经被其他应用程序锁住</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>资料库在服务器上被删除</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>访问本地文件夹时出错</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>初始化...</translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation>索引本地文件失败</translation>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation>获取服务器信息失败</translation>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation>创建本地文件失败</translation>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation>合并本地修改失败</translation>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation>密码错误。请重新下载</translation>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation>内部错误</translation>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>连接服务器...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>索引文件...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation>下载文件列表中 ...</translation>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation>下载文件中 ...</translation>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>创建文件夹...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>合并文件更改...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>完成</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation>连接服务器...</translation>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>取消中</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>已取消</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL 错误</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>网络错误:%1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>服务器内部错误</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>打开证书数据库时失败</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>文件 &quot;%1&quot; 不存在于路径 &quot;%2&quot; 中</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 找不到合适的程序来打开文件 %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>创建了资料库 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>删除了资料库 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>将 %1 重命名为</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>无法下载 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>复制文件失败</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>添加了</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>删除了</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>删除了</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>修改了</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>重命名了</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation>添加或修改了</translation>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>移动了</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>添加了文件夹</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>删除了文件夹</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>重命名了文件夹</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>移动了文件夹</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>文件</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>文件夹</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>及其他 %1 个</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>资料库状态恢复到</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>文件 &quot;%1&quot; 状态恢复到 %2。</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>恢复了删除的文件夹</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>更改了资料库的名字或描述</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation>系统自动合并更改</translation>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>刚才</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>1 天前</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 天前</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>1 小时前</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 小时前</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>1 分钟前</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 分钟前</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;不包含这部分信息&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>同步此资料库于:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>同步此文件夹于:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>文件夹</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>只读文件夹</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>文档</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF 文档</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>图片</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>文本文件</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>音乐文件</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>视频文件</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Word文档</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>PowerPoint文档</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Excel文档</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation>路径 &quot;%1&quot; 与系统路径冲突</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation>路径 &quot;%1&quot; 与已有资料库冲突</translation>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation>上传文件列表</translation>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation>文件已经被其他应用程序锁定</translation>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation>文件夹已经被其他应用程序锁定</translation>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation>文件已经被其他用户锁定</translation>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation>文件路径非法</translation>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation>索引文件时出错</translation>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation>文件路径以空格或点号结尾</translation>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation>文件路径中包含类似 &quot;|&quot; 和 &quot;:&quot; 的非法字符</translation>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation>打开文件缓存数据库失败</translation>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation>资料库名称包含非法字符例如&quot;:&quot;,&quot;*&quot;,&quot;|&quot;,&quot;?&quot;</translation>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation>文件夹权限设置导致文件无法被更新</translation>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation>%1 已经在运行中</translation>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation>上传过程中出错</translation>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation>下载过程中出错</translation>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation>权限错误。请尝试重新同步该资料库</translation>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation>客户端数据损坏。请尝试重新同步该资料库</translation>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation>对该库没有写权限</translation>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation>没有权限同步该资料库</translation>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation>没有权限同步此文件夹</translation>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation>删除了回收站中的所有条目</translation>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation>删除了回收站中 %1 天前的条目</translation>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation>发布草稿</translation>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation>创建草稿</translation>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation>创建文件</translation>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation>重命名文件</translation>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation>删除草稿</translation>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation>删除文件</translation>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation>恢复文件</translation>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation>移动文件</translation>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation>更新文件</translation>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation>创建文件夹</translation>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation>重命名文件夹</translation>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation>删除文件夹</translation>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation>恢复文件夹</translation>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation>移动文件夹</translation>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation>创建了资料库</translation>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation>重命名资料库</translation>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation>删除了资料库</translation>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation>恢复资料库</translation>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation>只读资料库下的文件改动不会被上传</translation>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation>文件不存在</translation>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>资料库 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>这个资料库还没有下载到本地</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>错误: </translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation>%1 秒</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>资料库图标</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>资料库名字</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>文本</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>所有者:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>更新时间:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>修改时间</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>大小:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>本地路径:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>状态:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>资料库状态</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>名字:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation>同步间隔:</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>关闭</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>这个资料库还没有下载</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>无法打开不存在的资料库 &quot;%2&quot; 中的文件 &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>最近修改</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>我的资料库</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>子资料库</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation>共享给我的</translation>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation>公共</translation>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation>群组共享</translation>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>已同步资料库</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>初始化</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>关闭自动同步</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>打开自动同步</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>详情(&amp;D)</translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>查看该资料库详细信息</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>同步该资料库(&amp;S)</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>同步这个资料库</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>最近修改</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>立即同步(&amp;S)</translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>立即同步资料库</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>取消下载(&amp;C)</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>取消下载这个资料库</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>打开文件夹(&amp;O)</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>打开本地文件夹</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation>打开本地文件夹(&amp;O)</translation>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>解除同步(&amp;U)</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>解除同步这个资料库</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>到网站上查看(&amp;V)</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>到网站上查看这个资料库</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation>共享给其他用户</translation>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation>把这个资料库共享给其他用户</translation>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation>共享给群组</translation>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation>把这个资料库共享给某个群组</translation>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>打开云端文件浏览器(&amp;O)</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>用内嵌的云端文件浏览器,打开此资料库</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation>退出共享(&amp;L)</translation>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation>退出共享</translation>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>重新同步此资料库 (&amp;R)</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>解除同步这个资料库 然后重新同步</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation>设置同步间隔 (&amp;I)</translation>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation>设置资料库 “%1” 的同步间隔</translation>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation>您确定要解除同步资料库 &quot;%1&quot; 吗?</translation>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation>您确定要解除同步资料库 &quot;%1&quot; 吗?</translation>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation>您真的想覆盖文件 &quot;%1&quot; 吗?</translation>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>解除同步资料库 &quot;%1&quot; 失败</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation>您真的想退出共享 &quot;%1&quot; 吗?</translation>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation>退出共享失败</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>取消任务失败:%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>下载已取消</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation>您没有权限上传文件到这个文件夹</translation>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>无法用文件 &quot;%1&quot; 覆盖自身</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>无法删移文件 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>上传文件失败: %1</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation>同步间隔 (秒)</translation>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation>设置资料库 “%1” 的同步间隔</translation>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation>搜索资料库</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>重试</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>获取资料库信息失败&lt;br/&gt;请 %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;警告:&lt;/b&gt; 该服务器的SSL 证书不可信,是否继续?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation>添加默认帐户失败</translation>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>初始化日志失败: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>确定</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>是</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>否</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation>保存客户端 ID 失败</translation>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation>访问 %1 失败</translation>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation>错误的客户端 ID</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>读取文件 %1 失败</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation>%1 内部链接</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>复制至剪贴板</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>确定</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation>%1 内部链接</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>未知错误</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation>内部错误:连接 daemon 失败</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>关闭自动同步</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>打开自动同步</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>退出(&amp;Q)</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>显示主窗口</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>设置</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>打开 %1 文件夹(&amp;F)</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>打开 %1 文件夹</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>打开日志文件夹(&amp;L)</translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation>查看文件同步错误</translation>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>关于(&amp;A)</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>显示关于对话框</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>在线帮助(&amp;O)</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>文件</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>自动同步已关闭</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>正在上传</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>正在下载</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>打开 %1 日志文件夹</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>打开 %1 在线帮助文档</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>一些服务器未连接</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation>上传日志文件</translation>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation>上传 %1 日志文件</translation>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation>请先登录</translation>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation>修复文件管理器扩展</translation>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation>修复文件管理器扩展成功</translation>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation>修复文件管理器扩展失败</translation>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation>打开所在文件夹(&amp;S)</translation>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation>打开所在文件夹</translation>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation>搜索文件</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>重试</translation>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation>搜索失败&lt;br/&gt;请 %1</translation>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>服务器连接状态</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>已连接</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>未连接</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>关闭</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>请输入资料库密码</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>请输入资料库 %1 的密码</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>请输入密码</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>错误的密码</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>未知错误</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>确定</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>设置</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation>开机自动启动 %1</translation>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation>不要在 dock 中显示 %1 图标</translation>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>没有代理</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP 代理</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>SOCKS5 代理</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation>系统代理</translation>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>您已经更改了语言。现在重启来生效吗?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation>代理服务器名不能为空</translation>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation>代理端口不正确</translation>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation>代理用户名不能为空</translation>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation>代理用户密码不能为空</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>启动时隐藏主窗口</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>资料库同步后用气泡通知</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>允许同步 office 临时文件</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>最大下载速度 (kB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>最大上传速度 (kB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>基本</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>不自动解除资料库同步</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>当资料库的本地文件夹被移除或无法访问时不自动解除同步。</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>当在服务器找不到某个资料库的信息时不要自动解除同步</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>当在服务器找不到某个资料库的信息时不要自动解除同步</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>启用 Finder 的扩展</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>启用文件浏览器的扩展</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation>自动检查更新</translation>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>HTTPS 同步过程中不验证服务器证书</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>启用与已存在的其他文件夹同步的选项</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>高级</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>语言 (需要重启)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>语言</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>代理类型:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>主机:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>端口:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>用户名:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>密码:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>代理服务器需要密码</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>网络</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>确定</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation>可读写</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>只读</translation>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation>删除共享</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation>点击开始编辑</translation>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation>由 %1 创建</translation>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation>可读写</translation>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation>只读</translation>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation>群组</translation>
+    </message>
+    <message>
+        <source>User</source>
+        <translation>用户</translation>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation>权限</translation>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation>上一个操作还未完成</translation>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>共享链接</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>共享链接:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>直接下载</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>复制至剪贴板</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>确认</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation>使用 Shibboleth 登录</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>保存当前账号失败</translation>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>不安全的连接</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 使用了不合法的安全证书,该网络连接可能不安全。是否继续?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>当前 RSA 密钥指纹是 %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>过去的 RSA 密钥指纹是 %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>记住我的选择</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>是</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>否</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>打开(&amp;O)</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>打开这个文件</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>在网站上查看(&amp;W)</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>在网站上查看这个文件</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>重试</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>获取星标文件信息失败。&lt;br/&gt;请 %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>您还没有星标文件。</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation>文件同步错误</translation>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation>没有同步错误</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation>双击打开资料库</translation>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation>资料库</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>路径</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>错误</translation>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation>时间</translation>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation>请输入两步验证的动态口令</translation>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation>两步验证</translation>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation>请输入两步验证的动态口令</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation>mText</translation>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation>记住该设备</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>确定</translation>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>卸载 %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>是否删除 %1 帐号信息?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>删除帐户信息...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>对话框</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>text</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>是</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>否</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/i18n/seafile_zh_TW.ts b/i18n/seafile_zh_TW.ts
new file mode 100644 (file)
index 0000000..994d182
--- /dev/null
@@ -0,0 +1,3297 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_TW" version="2.1">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <source>About %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h2&gt;%1 Client %2&lt;/h2&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&lt;h5&gt; REV %1 &lt;/h5&gt;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>About</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Check For Updates</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountManager</name>
+    <message>
+        <source>failed to open account database</source>
+        <translation>無法開啟帳號數據庫</translation>
+    </message>
+    <message>
+        <source>Authorization expired, please re-login</source>
+        <translation>帳號驗證訊息已過期,請重新登入</translation>
+    </message>
+    <message>
+        <source>Failed to remove local repos sync token: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get repo sync information from server: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AccountSettingsDialog</name>
+    <message>
+        <source>Account Settings</source>
+        <translation>帳號設定</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>請輸入伺服器位置</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 不是有效的伺服器位置</translation>
+    </message>
+    <message>
+        <source>Failed to save account information</source>
+        <translation>無法存儲帳號訊息</translation>
+    </message>
+    <message>
+        <source>Failed to save the changes: %1</source>
+        <translation>無法儲存以下更改: %1</translation>
+    </message>
+    <message>
+        <source>Successfully updated current account information</source>
+        <translation>成功更新目前帳號訊息</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>Server Address</source>
+        <translation>伺服器位置</translation>
+    </message>
+    <message>
+        <source>Email</source>
+        <translation>電子郵件</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>確認</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>AccountView</name>
+    <message>
+        <source>Are you sure you want to remove account %1?&lt;br&gt;&lt;br&gt;The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync libraries of this account: %1</source>
+        <translation>無法解除同步此帳號下的資料庫 %1</translation>
+    </message>
+    <message>
+        <source>click to open the website</source>
+        <translation>開啟檢視網頁端</translation>
+    </message>
+    <message>
+        <source>pro version</source>
+        <translation>專業版</translation>
+    </message>
+    <message>
+        <source>No account</source>
+        <translation>沒有可用帳號</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>選擇</translation>
+    </message>
+    <message>
+        <source>Account settings</source>
+        <translation>帳號設定</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>登入</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>刪除</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>增加新的帳號</translation>
+    </message>
+    <message>
+        <source>Logout</source>
+        <translation>登出</translation>
+    </message>
+    <message>
+        <source>not logged in</source>
+        <translation>尚未登陸</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>表單</translation>
+    </message>
+    <message>
+        <source>Account</source>
+        <translation>帳號</translation>
+    </message>
+    <message>
+        <source>email</source>
+        <translation>電子郵件</translation>
+    </message>
+    <message>
+        <source>server</source>
+        <translation>伺服器</translation>
+    </message>
+</context>
+<context>
+    <name>ActivitiesTab</name>
+    <message>
+        <source>File Activities are only supported in %1 Server Professional Edition.</source>
+        <translation>很抱歉,但是此功能只在 %1 專業版本提供支援</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>重新嘗試</translation>
+    </message>
+    <message>
+        <source>Failed to get actvities information. Please %1</source>
+        <translation>無法獲取變動資訊,請 %1</translation>
+    </message>
+</context>
+<context>
+    <name>AutoUpdateManager</name>
+    <message>
+        <source>Upload Success</source>
+        <translation>上傳成功</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+uploaded successfully.</source>
+        <translation>檔案 &quot;%1&quot;
+成功上傳。</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot;
+failed to upload.</source>
+        <translation>檔案 &quot;%1&quot;
+無法上傳。</translation>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The file is locked by %1, please try again later</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload Failure: %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>AvatarService</name>
+    <message>
+        <source>Failed to create avatars folder</source>
+        <translation>無法建立大頭照資料夾</translation>
+    </message>
+</context>
+<context>
+    <name>CheckRepoRootDirPermDialog</name>
+    <message>
+        <source>Checking Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>CloneTasksDialog</name>
+    <message>
+        <source>Download tasks</source>
+        <translation>下載任務</translation>
+    </message>
+    <message>
+        <source>remove all successful tasks</source>
+        <translation>刪除所有已完成的任務</translation>
+    </message>
+    <message>
+        <source>No download tasks right now.</source>
+        <translation>目前沒有下載任務</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>清除</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>關閉</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableModel</name>
+    <message>
+        <source>Library</source>
+        <translation>資料庫</translation>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation>路徑</translation>
+    </message>
+</context>
+<context>
+    <name>CloneTasksTableView</name>
+    <message>
+        <source>Cancel this task</source>
+        <translation>取消這項任務</translation>
+    </message>
+    <message>
+        <source>cancel this task</source>
+        <translation>取消這項任務</translation>
+    </message>
+    <message>
+        <source>Remove this task</source>
+        <translation>刪除這項任務</translation>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>無法取消這項任務:
+
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to remove this task:
+
+ %1</source>
+        <translation>無法刪除這項任務:
+
+%1</translation>
+    </message>
+</context>
+<context>
+    <name>CloudView</name>
+    <message>
+        <source>Minimize</source>
+        <translation>視窗最小化</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>關閉</translation>
+    </message>
+    <message>
+        <source>Libraries</source>
+        <translation>資料庫</translation>
+    </message>
+    <message>
+        <source>Starred</source>
+        <translation>標示</translation>
+    </message>
+    <message>
+        <source>Activities</source>
+        <translation>事件</translation>
+    </message>
+    <message>
+        <source>Search</source>
+        <translation>檢索</translation>
+    </message>
+    <message>
+        <source>current download rate</source>
+        <translation>目前下載速率</translation>
+    </message>
+    <message>
+        <source>current upload rate</source>
+        <translation>目前上載速率</translation>
+    </message>
+    <message>
+        <source>Please Choose a folder to sync</source>
+        <translation>請選擇空閒目錄以用於同步</translation>
+    </message>
+    <message>
+        <source>no server connected</source>
+        <translation>沒有到伺服器的連接</translation>
+    </message>
+    <message>
+        <source>all servers connected</source>
+        <translation>到伺服器的連接正常運作中</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>到伺服器的鏈路部分運作中</translation>
+    </message>
+    <message>
+        <source>Form</source>
+        <translation>表單</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>圖示</translation>
+    </message>
+    <message>
+        <source>minimize</source>
+        <translation>視窗最小化</translation>
+    </message>
+    <message>
+        <source>close</source>
+        <translation>關閉</translation>
+    </message>
+    <message>
+        <source>...</source>
+        <translation>更多</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>選擇</translation>
+    </message>
+    <message>
+        <source>brand</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>or Drop Folder to Sync</source>
+        <translation>或者拖拽目錄到此處 進行同步</translation>
+    </message>
+    <message>
+        <source>download rate</source>
+        <translation>下載速率</translation>
+    </message>
+    <message>
+        <source>downarrow</source>
+        <translation>向下箭頭</translation>
+    </message>
+    <message>
+        <source>upload rate</source>
+        <translation>上傳速率</translation>
+    </message>
+    <message>
+        <source>uparrow</source>
+        <translation>向上箭頭</translation>
+    </message>
+</context>
+<context>
+    <name>Configurator</name>
+    <message>
+        <source>Error when creating ccnet configuration</source>
+        <translation>在建立ccnet設定檔案時候遭遇錯誤</translation>
+    </message>
+    <message>
+        <source>Unable to create preconfigure directory &quot;%1&quot;</source>
+        <translation>無法建立預配置資料夾 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation>無法讀取 %1</translation>
+    </message>
+</context>
+<context>
+    <name>CreateRepoDialog</name>
+    <message>
+        <source>Create a library</source>
+        <translation>建立新的資料庫</translation>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>請選擇空閒目錄以用於同步</translation>
+    </message>
+    <message>
+        <source>Creating...</source>
+        <translation>建立 ...</translation>
+    </message>
+    <message>
+        <source>Failed to generate encryption key for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose the directory to sync</source>
+        <translation>請選擇空閒目錄以用於同步</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>目錄 %1 不存在</translation>
+    </message>
+    <message>
+        <source>Please enter the name</source>
+        <translation>請輸入名稱</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>請輸入保護密碼</translation>
+    </message>
+    <message>
+        <source>Passwords don&apos;t match</source>
+        <translation>密碼無法匹配</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>遭遇未知錯誤</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>無法增加新的下載任務:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create library on the server:
+%1</source>
+        <translation>無法在伺服器上建立新的資料庫:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>Path:</source>
+        <translation>路徑:</translation>
+    </message>
+    <message>
+        <source>Choose</source>
+        <translation>選擇</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>名稱:</translation>
+    </message>
+    <message>
+        <source>encrypted</source>
+        <translation>已加密</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>密碼:</translation>
+    </message>
+    <message>
+        <source>Password Again:</source>
+        <translation>重複密碼:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>狀態文字</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>確認</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>DaemonManager</name>
+    <message>
+        <source>%1 client failed to initialize</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 exited unexpectedly</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>DownloadRepoDialog</name>
+    <message>
+        <source>Please enter the password</source>
+        <translation>請輸入保護密碼</translation>
+    </message>
+    <message>
+        <source>Sync library &quot;%1&quot;</source>
+        <translation>同步資料庫 %1</translation>
+    </message>
+    <message>
+        <source>Sync folder &quot;%1&quot;</source>
+        <translation>同步目錄 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync to folder:</source>
+        <translation>同步到資料夾:</translation>
+    </message>
+    <message>
+        <source>or</source>
+        <translation>或著</translation>
+    </message>
+    <message>
+        <source>sync with an existing folder</source>
+        <translation>於已有的資料夾同步</translation>
+    </message>
+    <message>
+        <source>create a new sync folder</source>
+        <translation>創建一個新的同步資料夾</translation>
+    </message>
+    <message>
+        <source>Sync with this existing folder:</source>
+        <translation>與這個已存在的資料夾同步:</translation>
+    </message>
+    <message>
+        <source>Please choose a folder</source>
+        <translation>請選擇一個資料夾</translation>
+    </message>
+    <message>
+        <source>The folder does not exist</source>
+        <translation>此資料夾不存在</translation>
+    </message>
+    <message>
+        <source>Please choose the folder to sync.</source>
+        <translation>請選擇一個用於同步的資料夾。</translation>
+    </message>
+    <message>
+        <source>Your organization disables putting a library outside %1 folder.</source>
+        <translation>您的組織已經屏蔽將資料庫同步於 %1 目錄外的功能。</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing file &quot;%1&quot;, please choose a different folder.</source>
+        <translation>與已有檔案 &quot;%1&quot; 發生衝突,請選擇其他資料夾。</translation>
+    </message>
+    <message>
+        <source>Conflicting with existing library &quot;%1&quot;, please choose a different folder.</source>
+        <translation>與已有的資料庫 &quot;%1&quot; 發生衝突,請選擇其他資料夾。</translation>
+    </message>
+    <message>
+        <source>The folder &quot;%1&quot; already exists. Are you sure to sync with it (contents will be merged)?</source>
+        <translation>資料夾 &quot;%1&quot; 已經存在。 請問您是否與之同步 (內容會被合併) ?</translation>
+    </message>
+    <message>
+        <source>Click No to sync with a new folder instead</source>
+        <translation>點擊“否” 則與一個新的資料夾同步</translation>
+    </message>
+    <message>
+        <source>Unable to find an alternative folder name</source>
+        <translation>無法找到其他合適的資料夾名稱</translation>
+    </message>
+    <message>
+        <source>Failed to add download task:
+ %1</source>
+        <translation>無法增加新的下載任務:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to get repo download information:
+%1</source>
+        <translation>無法獲取資料庫的下載檔案:
+%1</translation>
+    </message>
+    <message>
+        <source>Download Library</source>
+        <translation>下載資料庫</translation>
+    </message>
+    <message>
+        <source>choose...</source>
+        <translation>選取...</translation>
+    </message>
+    <message>
+        <source>Password for this library:</source>
+        <translation>此資料庫的密碼:</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>確認</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsDialog</name>
+    <message>
+        <source>Modification Details</source>
+        <translation>詳細的修改差異集</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListModel</name>
+    <message>
+        <source>Added files</source>
+        <translation>已添加的檔案</translation>
+    </message>
+    <message>
+        <source>Deleted files</source>
+        <translation>已刪除的檔案</translation>
+    </message>
+    <message>
+        <source>Modified files</source>
+        <translation>已修改的檔案</translation>
+    </message>
+    <message>
+        <source>Added folders</source>
+        <translation>已添加的資料夾</translation>
+    </message>
+    <message>
+        <source>Deleted folders</source>
+        <translation>已刪除的資料夾</translation>
+    </message>
+</context>
+<context>
+    <name>EventDetailsListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>打開(&amp;O)
+</translation>
+    </message>
+    <message>
+        <source>Open &amp;parent folder</source>
+        <translation>打開父資料夾(&amp;P)</translation>
+    </message>
+</context>
+<context>
+    <name>FileBrowserDialog</name>
+    <message>
+        <source>Cloud File Browser</source>
+        <translation>雲端檔案瀏覽器</translation>
+    </message>
+    <message>
+        <source>Back</source>
+        <translation>回退</translation>
+    </message>
+    <message>
+        <source>Forward</source>
+        <translation>前進</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>根目錄</translation>
+    </message>
+    <message>
+        <source>Upload files</source>
+        <translation>上傳多個檔案</translation>
+    </message>
+    <message>
+        <source>Upload a directory</source>
+        <translation>上傳目錄</translation>
+    </message>
+    <message>
+        <source>You don&apos;t have permission to upload files to this library</source>
+        <translation>您沒有權限上傳檔案到這個資料庫</translation>
+    </message>
+    <message>
+        <source>Create a folder</source>
+        <translation>新建目錄</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 items</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder name</source>
+        <translation>資料夾名稱</translation>
+    </message>
+    <message>
+        <source>Invalid folder name!</source>
+        <translation>無效的目錄名稱!</translation>
+    </message>
+    <message>
+        <source>The name &quot;%1&quot; is already taken.</source>
+        <translation>名稱 &quot;%1&quot; 已經被佔用了。</translation>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>重新嘗試</translation>
+    </message>
+    <message>
+        <source>Failed to get files information&lt;br/&gt;Please %1</source>
+        <translation>無法獲取檔案訊息&lt;br/&gt;
+請 %1</translation>
+    </message>
+    <message>
+        <source>This folder is empty.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter name of file to save to...</source>
+        <translation>請輸入需要另存為的檔案名稱...</translation>
+    </message>
+    <message>
+        <source>Unable to remove file &quot;%1&quot;</source>
+        <translation>無法刪除檔案 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Enter the path of the folder you want to save to...</source>
+        <translation>請輸入需要另存到的資料檔的路徑...</translation>
+    </message>
+    <message>
+        <source>Do you want to overwrite the existing file &quot;%1&quot;?</source>
+        <translation>您真的想刪除已有檔案 &quot;%1&quot; 嗎?</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; haven&apos;t been synced</source>
+        <translation>檔案 &quot;%1&quot; 沒有被同步</translation>
+    </message>
+    <message>
+        <source>File %1 already exists.&lt;br/&gt;Do you like to overwrite it?&lt;br/&gt;&lt;small&gt;(Choose No to upload using an alternative name).&lt;/small&gt;</source>
+        <translation>檔案 %1 已經存在。&lt;br/&gt;您想覆蓋它嗎?&lt;br/&gt;&lt;small&gt;(選 否 會使用不同的名字)。&lt;/small&gt;</translation>
+    </message>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to download file: %1</source>
+        <translation>無法下載檔案:%1</translation>
+    </message>
+    <message>
+        <source>Select a file to upload</source>
+        <translation>請選擇需要上傳的檔案</translation>
+    </message>
+    <message>
+        <source>Select a directory to upload</source>
+        <translation>選擇你需要上傳的目錄</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>重命名</translation>
+    </message>
+    <message>
+        <source>Do you really want to delete these items</source>
+        <translation>您真的想刪除這些檔案嗎?</translation>
+    </message>
+    <message>
+        <source>Create folder failed</source>
+        <translation>建立目錄失敗</translation>
+    </message>
+    <message>
+        <source>Lock file failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Select a file to update %1</source>
+        <translation>請選擇需要上傳的檔案 以更新 %1</translation>
+    </message>
+    <message>
+        <source>Rename failed</source>
+        <translation>重命名失敗</translation>
+    </message>
+    <message>
+        <source>Remove failed</source>
+        <translation>刪除失敗</translation>
+    </message>
+    <message>
+        <source>Share failed</source>
+        <translation>分享失敗</translation>
+    </message>
+    <message>
+        <source>Cannot paste files from the same folder</source>
+        <translation>無法從相同的目錄拷貝檔案</translation>
+    </message>
+    <message>
+        <source>Cannot paste the folder to its subfolder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy failed</source>
+        <translation>複製失敗</translation>
+    </message>
+    <message>
+        <source>Move failed</source>
+        <translation>移動失敗</translation>
+    </message>
+    <message>
+        <source>Create library failed!</source>
+        <translation>建立目錄失敗!</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to upload file %1: %2</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to create cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to open cache folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserProgressDialog</name>
+    <message>
+        <source>Pending</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation>上傳</translation>
+    </message>
+    <message>
+        <source>Uploading %1</source>
+        <translation>正在上傳 %1</translation>
+    </message>
+    <message>
+        <source>Download</source>
+        <translation>下載</translation>
+    </message>
+    <message>
+        <source>Downloading %1</source>
+        <translation>正在下載 %1</translation>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation>已完成 %2 中的 %1</translation>
+    </message>
+    <message>
+        <source>Failed to upload file &quot;%1&quot;, do you want to retry?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Saving</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File save failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Index progress request error %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchModel</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileBrowserSearchView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileNetworkTask</name>
+    <message>
+        <source>Operation canceled</source>
+        <translation>操作已取消</translation>
+    </message>
+    <message>
+        <source>pending</source>
+        <translation>等待中</translation>
+    </message>
+</context>
+<context>
+    <name>FileServerTask</name>
+    <message>
+        <source>task cancelled</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>內部伺服器錯誤</translation>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableModel</name>
+    <message>
+        <source>locked by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation>名稱</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation>檔案大小</translation>
+    </message>
+    <message>
+        <source>Last Modified</source>
+        <translation>最後修改日期</translation>
+    </message>
+    <message>
+        <source>Modifier</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FileTableView</name>
+    <message>
+        <source>&amp;Save As...</source>
+        <translation>另存為... (&amp;S)</translation>
+    </message>
+    <message>
+        <source>&amp;Lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Rename</source>
+        <translation>重命名(&amp;R)</translation>
+    </message>
+    <message>
+        <source>&amp;Delete</source>
+        <translation>刪除(&amp;D)</translation>
+    </message>
+    <message>
+        <source>Share to Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Update</source>
+        <translation>更新(&amp;U)</translation>
+    </message>
+    <message>
+        <source>&amp;Copy</source>
+        <translation>複製 (&amp;C)</translation>
+    </message>
+    <message>
+        <source>Cu&amp;t</source>
+        <translation>剪貼 (&amp;T)</translation>
+    </message>
+    <message>
+        <source>&amp;Paste</source>
+        <translation>粘貼 (&amp;P)</translation>
+    </message>
+    <message>
+        <source>Canc&amp;el Download</source>
+        <translation>取消下載(&amp;C)</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this folder</source>
+        <translation>同步此資料夾 (&amp;S)</translation>
+    </message>
+    <message>
+        <source>This feature is available in pro version only
+</source>
+        <translation>此功能只在專業版中提供</translation>
+    </message>
+    <message>
+        <source>&amp;Generate %1 Download Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>G&amp;enerate %1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Save As To...</source>
+        <translation>另存到... (&amp;S)</translation>
+    </message>
+    <message>
+        <source>Un&amp;lock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to remove readonly files</source>
+        <translation>無法刪除只讀文件</translation>
+    </message>
+    <message>
+        <source>Unable to cut readonly files</source>
+        <translation>無法剪切只讀文件</translation>
+    </message>
+    <message>
+        <source>Retry Upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Delete Local Version</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Local Version Save As...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Open Local Cache Folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>FinderSyncHost</name>
+    <message>
+        <source>Failed to get link</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>GetFileTask</name>
+    <message>
+        <source>Failed to create folders</source>
+        <translation>無法建立資料夾</translation>
+    </message>
+    <message>
+        <source>Failed to create temporary files</source>
+        <translation>無法建立臨時檔案</translation>
+    </message>
+    <message>
+        <source>Failed to write file to disk</source>
+        <translation>無法將檔案寫入磁盤</translation>
+    </message>
+    <message>
+        <source>Failed to remove the older version of the downloaded file</source>
+        <translation>無法刪除已下載的檔案</translation>
+    </message>
+    <message>
+        <source>Failed to move file</source>
+        <translation>無法刪除檔案</translation>
+    </message>
+</context>
+<context>
+    <name>InitSeafileDialog</name>
+    <message>
+        <source>%1 Initialization</source>
+        <translation>%1 還在初始化</translation>
+    </message>
+    <message>
+        <source>Choose %1 folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a directory</source>
+        <translation>請選擇空閒目錄以用於同步</translation>
+    </message>
+    <message>
+        <source>Initialization is not finished. Really quit?</source>
+        <translation>初始化還沒有完成,確認現在退出?</translation>
+    </message>
+    <message>
+        <source>The folder %1 does not exist</source>
+        <translation>目錄 %1 並不存在</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>圖示</translation>
+    </message>
+    <message>
+        <source>Choose a folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Choose...</source>
+        <translation>選取...</translation>
+    </message>
+    <message>
+        <source>Next</source>
+        <translation>下一步</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>InitVirtualDriveDialog</name>
+    <message>
+        <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Checking your default library...</source>
+        <translation>正在檢查您的默認資料庫...</translation>
+    </message>
+    <message>
+        <source>Creating the default library...</source>
+        <translation>正在建立默認資料庫...</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+        <translation>無法建立默認資料庫:
+
+此項功能只在伺服器版本2.1或者之上被支援</translation>
+    </message>
+    <message>
+        <source>Failed to get default library:
+%1</source>
+        <translation>無法取得默認資料庫:
+%1</translation>
+    </message>
+    <message>
+        <source>Failed to create default library:
+%1</source>
+        <translation>無法建立默認資料庫:
+%1</translation>
+    </message>
+    <message>
+        <source>Downloading default library...</source>
+        <translation>正在下載默認資料庫...</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+%1</source>
+        <translation>無法下載默認資料庫:
+%1</translation>
+    </message>
+    <message>
+        <source>The default library has been downloaded.
+You can click the &quot;Open&quot; button to view it.</source>
+        <translation>默認資料庫已下載完畢。
+您可以點擊“開啟”查看。</translation>
+    </message>
+    <message>
+        <source>Error when downloading the default library: %1</source>
+        <translation>在下載默認資料庫的時候遭遇錯誤:%1</translation>
+    </message>
+    <message>
+        <source>Failed to download default library:
+ %1</source>
+        <translation>無法下載默認資料庫:
+%1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>%1 organizes files by libraries. 
+Do you like to download your default library?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Skip</source>
+        <translation>略過</translation>
+    </message>
+    <message>
+        <source>Run in Background</source>
+        <translation>後台模式運行</translation>
+    </message>
+    <message>
+        <source>Open</source>
+        <translation>開啟</translation>
+    </message>
+    <message>
+        <source>Finish</source>
+        <translation>完結</translation>
+    </message>
+    <message>
+        <source>Download Default Library</source>
+        <translation>下載默認資料庫</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>好</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>圖示</translation>
+    </message>
+</context>
+<context>
+    <name>LoadMoreButton</name>
+    <message>
+        <source>load more</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogDirUploader</name>
+    <message>
+        <source>Upload log files failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission Error!</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library/Folder not found.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Authorization expired</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Upload log files failed :%1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully uploaded log files</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogUploadProgressDialog</name>
+    <message>
+        <source>Compressing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 of %2</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LoginDialog</name>
+    <message>
+        <source>Add an account</source>
+        <translation>增加新的帳號</translation>
+    </message>
+    <message>
+        <source>Single Sign On</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Re-login</source>
+        <translation>重新登陸</translation>
+    </message>
+    <message>
+        <source>Logging in...</source>
+        <translation>登入中...</translation>
+    </message>
+    <message>
+        <source>Network Error:
+ %1</source>
+        <translation>網路錯誤:
+%1</translation>
+    </message>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;警告:&lt;/b&gt; 伺服器的SSL證書不被信任,請問還需要繼續操作嗎?</translation>
+    </message>
+    <message>
+        <source>Please enter the server address</source>
+        <translation>請輸入伺服器地址</translation>
+    </message>
+    <message>
+        <source>%1 is not a valid server address</source>
+        <translation>%1 不是有效的伺服器地址</translation>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation>請輸入用戶名</translation>
+    </message>
+    <message>
+        <source>Please enter the computer name</source>
+        <translation>請輸入此計算機的代號</translation>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation>無法儲存目前帳號</translation>
+    </message>
+    <message>
+        <source>%1 Server Address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server address must not be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 is not a valid server address. It has to start with &apos;https://&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>請輸入保護密碼</translation>
+    </message>
+    <message>
+        <source>Incorrect email or password</source>
+        <translation>無法理解的郵件地址或者密碼</translation>
+    </message>
+    <message>
+        <source>Logging in too frequently, please wait a minute</source>
+        <translation>嘗試展登入過於頻繁,請稍後嘗試</translation>
+    </message>
+    <message>
+        <source>Internal Server Error</source>
+        <translation>內部伺服器錯誤</translation>
+    </message>
+    <message>
+        <source>Failed to login: %1</source>
+        <translation>無法登入:%1</translation>
+    </message>
+    <message>
+        <source>Failed to login</source>
+        <translation>無法登入</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>logo</source>
+        <translation>圖示</translation>
+    </message>
+    <message>
+        <source>Server:</source>
+        <translation>伺服器:</translation>
+    </message>
+    <message>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;比如 https://seacloud.cc &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <source>or http://192.168.1.24:8000</source>
+        <translation>或者 http://192.168.1.24:8000</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>密碼:</translation>
+    </message>
+    <message>
+        <source>status text</source>
+        <translation>狀態文字</translation>
+    </message>
+    <message>
+        <source>Computer Name:</source>
+        <translation>計算機代號:</translation>
+    </message>
+    <message>
+        <source>Email / Username:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>e.g. Jim&apos;s laptop</source>
+        <translation>比如 Jim 的本本</translation>
+    </message>
+    <message>
+        <source>Login</source>
+        <translation>登入</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+    <message>
+        <source>Automatic Login</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>LogoutView</name>
+    <message>
+        <source>You are logout. Please </source>
+        <translation>您已登出。請</translation>
+    </message>
+    <message>
+        <source>login</source>
+        <translation>登入</translation>
+    </message>
+    <message>
+        <source>Add an account</source>
+        <translation>增加新的帳號</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Refresh</source>
+        <translation>重新整理</translation>
+    </message>
+</context>
+<context>
+    <name>MessagePoller</name>
+    <message>
+        <source>&quot;%1&quot; is unsynced. 
+Reason: Deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; is synchronized</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Files uploaded to &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File %1 conflict</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to index file %1
+Please check file permission and disk space.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file %1 is denied by folder permission setting.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync. 
+Access denied to service</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&quot;%1&quot; failed to sync.
+The library owner&apos;s storage space is used up.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync folder %1.</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>PrivateShareDialog</name>
+    <message>
+        <source>Share %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Enter user name or email address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share Operation Failed: %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed successfully</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get share information of the folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to get your groups and contacts information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the username</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the group name</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No such group &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to group %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Already shared to user %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share To:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read-Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>synchronized</source>
+        <translation>已同步</translation>
+    </message>
+    <message>
+        <source>indexing files</source>
+        <translation>正在索引檔案</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation>同步初始化完畢</translation>
+    </message>
+    <message>
+        <source>downloading</source>
+        <translation>正在下載</translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation>正在上傳</translation>
+    </message>
+    <message>
+        <source>sync merging</source>
+        <translation>同步合併中</translation>
+    </message>
+    <message>
+        <source>waiting for sync</source>
+        <translation>等待同步中</translation>
+    </message>
+    <message>
+        <source>server not connected</source>
+        <translation>沒有接入伺服器</translation>
+    </message>
+    <message>
+        <source>server authenticating</source>
+        <translation>正在和伺服器驗證身份</translation>
+    </message>
+    <message>
+        <source>auto sync is turned off</source>
+        <translation>自動同步已關閉</translation>
+    </message>
+    <message>
+        <source>unknown</source>
+        <translation>未知</translation>
+    </message>
+    <message>
+        <source>Server has been removed</source>
+        <translation>伺服器已被刪除</translation>
+    </message>
+    <message>
+        <source>You have not logged in to the server</source>
+        <translation>您還沒有登入過此伺服器</translation>
+    </message>
+    <message>
+        <source>You do not have permission to access this library</source>
+        <translation>您沒有訪問此資料庫的權限</translation>
+    </message>
+    <message>
+        <source>The storage space of the library owner has been used up</source>
+        <translation>配額用盡了...</translation>
+    </message>
+    <message>
+        <source>Remote service is not available</source>
+        <translation>遠程服務器不可用</translation>
+    </message>
+    <message>
+        <source>Access denied to service</source>
+        <translation>請求服務時被拒絕</translation>
+    </message>
+    <message>
+        <source>Internal data corrupted</source>
+        <translation>內部數據損毀</translation>
+    </message>
+    <message>
+        <source>Failed to start upload</source>
+        <translation>無法開始上傳</translation>
+    </message>
+    <message>
+        <source>Failed to start download</source>
+        <translation>無法開始下載</translation>
+    </message>
+    <message>
+        <source>Library is damaged on server</source>
+        <translation>資料庫在伺服器上的檔案已損毀</translation>
+    </message>
+    <message>
+        <source>Conflict in merge</source>
+        <translation>omg... 合併時候發生衝突</translation>
+    </message>
+    <message>
+        <source>Server version is too old</source>
+        <translation>伺服器版本過舊</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>遭遇未知錯誤</translation>
+    </message>
+    <message>
+        <source>Network error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve proxy address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot resolve server address</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cannot connect to server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to establish secure connection. Please check server SSL certificate</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer was interrupted. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Data transfer timed out. Please check network or firewall</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unhandled http redirect from server. Please check server cofiguration</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Server error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Bad request</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Not enough memory</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Storage quota full</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library deleted on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library damaged on server</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The storage quota has been used up</source>
+        <translation>空間配額已用盡</translation>
+    </message>
+    <message>
+        <source>Internal server error</source>
+        <translation>內部伺服器錯誤</translation>
+    </message>
+    <message>
+        <source>Your %1 client is too old</source>
+        <translation>您%1 的客戶端版本過舊</translation>
+    </message>
+    <message>
+        <source>Failed to sync this library</source>
+        <translation>無法同步此資料庫</translation>
+    </message>
+    <message>
+        <source>Files are locked by other application</source>
+        <translation>檔案已被其他應用程式鎖住</translation>
+    </message>
+    <message>
+        <source>Library is deleted on server</source>
+        <translation>伺服器已刪除此資料庫</translation>
+    </message>
+    <message>
+        <source>Error when accessing the local folder</source>
+        <translation>在開啟本地資料夾時候遭遇錯誤</translation>
+    </message>
+    <message>
+        <source>initializing...</source>
+        <translation>初始化中... </translation>
+    </message>
+    <message>
+        <source>Failed to index local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to check server information</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to create local files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to merge local file changes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Incorrect password. Please download again</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>connecting server...</source>
+        <translation>連接伺服器中...</translation>
+    </message>
+    <message>
+        <source>indexing files...</source>
+        <translation>索引檔案中...</translation>
+    </message>
+    <message>
+        <source>Downloading file list...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Downloading files...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Creating folder...</source>
+        <translation>建立資料夾中...</translation>
+    </message>
+    <message>
+        <source>Merge file changes...</source>
+        <translation>合併檔案衝突中...</translation>
+    </message>
+    <message>
+        <source>Done</source>
+        <translation>完成</translation>
+    </message>
+    <message>
+        <source>checking server info...</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Canceling</source>
+        <translation>取消中...</translation>
+    </message>
+    <message>
+        <source>Canceled</source>
+        <translation>已取消</translation>
+    </message>
+    <message>
+        <source>SSL Error</source>
+        <translation>SSL 安全證書錯誤</translation>
+    </message>
+    <message>
+        <source>Network Error: %1</source>
+        <translation>網路錯誤:%1</translation>
+    </message>
+    <message>
+        <source>Server Error</source>
+        <translation>伺服器錯誤</translation>
+    </message>
+    <message>
+        <source>failed to open certs database</source>
+        <translation>無法開啟證書數據庫</translation>
+    </message>
+    <message>
+        <source>File &quot;%1&quot; doesn&apos;t exist in &quot;%2&quot;</source>
+        <translation>檔案 &quot;%1&quot; 不存在於路徑 &quot;%2&quot; 中</translation>
+    </message>
+    <message>
+        <source>%1 couldn&apos;t find an application to open file %2</source>
+        <translation>%1 沒有能找到合適的應用程式開啟檔案 %2</translation>
+    </message>
+    <message>
+        <source>Created library &quot;%1&quot;</source>
+        <translation>建立新的資料庫 %1</translation>
+    </message>
+    <message>
+        <source>Deleted library &quot;%1&quot;</source>
+        <translation>刪除的資料庫 %1</translation>
+    </message>
+    <message>
+        <source>Rename %1 to</source>
+        <translation>將 %1 重命名為</translation>
+    </message>
+    <message>
+        <source>Unable to download item &quot;%1&quot;</source>
+        <translation>無法下載 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>copy failed</source>
+        <translation>複製失敗</translation>
+    </message>
+    <message>
+        <source>Added</source>
+        <translation>新增的</translation>
+    </message>
+    <message>
+        <source>Deleted</source>
+        <translation>刪除的</translation>
+    </message>
+    <message>
+        <source>Removed</source>
+        <translation>已被被刪除的</translation>
+    </message>
+    <message>
+        <source>Modified</source>
+        <translation>修改的</translation>
+    </message>
+    <message>
+        <source>Renamed</source>
+        <translation>重命名的</translation>
+    </message>
+    <message>
+        <source>Added or modified</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved</source>
+        <translation>移動的</translation>
+    </message>
+    <message>
+        <source>Added directory</source>
+        <translation>新增的資料夾</translation>
+    </message>
+    <message>
+        <source>Removed directory</source>
+        <translation>已被被刪除的資料夾</translation>
+    </message>
+    <message>
+        <source>Renamed directory</source>
+        <translation>重命名的資料夾</translation>
+    </message>
+    <message>
+        <source>Moved directory</source>
+        <translation>移動的資料夾</translation>
+    </message>
+    <message>
+        <source>files</source>
+        <translation>檔案</translation>
+    </message>
+    <message>
+        <source>directories</source>
+        <translation>目錄</translation>
+    </message>
+    <message>
+        <source>and %1 more</source>
+        <translation>還有 %1 等等</translation>
+    </message>
+    <message>
+        <source>Reverted library to status at</source>
+        <translation>恢復資料庫到狀態</translation>
+    </message>
+    <message>
+        <source>Reverted file &quot;%1&quot; to status at %2.</source>
+        <translation>恢復檔案 %1 到狀態 %2</translation>
+    </message>
+    <message>
+        <source>Recovered deleted directory</source>
+        <translation>恢復被刪除的資料夾</translation>
+    </message>
+    <message>
+        <source>Changed library name or description</source>
+        <translation>改變資料庫的名稱或者描述詞</translation>
+    </message>
+    <message>
+        <source>Auto merge by %1 system</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Just now</source>
+        <translation>就是現在</translation>
+    </message>
+    <message>
+        <source>1 day ago</source>
+        <translation>一天前</translation>
+    </message>
+    <message>
+        <source>%1 days ago</source>
+        <translation>%1 天前</translation>
+    </message>
+    <message>
+        <source>1 hour ago</source>
+        <translation>一小時前</translation>
+    </message>
+    <message>
+        <source>%1 hours ago</source>
+        <translation>%1 小時前</translation>
+    </message>
+    <message>
+        <source>1 minute ago</source>
+        <translation>一分鐘前</translation>
+    </message>
+    <message>
+        <source>%1 minutes ago</source>
+        <translation>%1 分鐘前</translation>
+    </message>
+    <message>
+        <source>&lt;Not Part of Certificate&gt;</source>
+        <translation>&lt;沒有包含在證書中&gt;</translation>
+    </message>
+    <message>
+        <source>Sync this library to:</source>
+        <translation>將此資料庫同步與:</translation>
+    </message>
+    <message>
+        <source>Sync this folder to:</source>
+        <translation>將此資料夾同步與:</translation>
+    </message>
+    <message>
+        <source>Folder</source>
+        <translation>資料夾</translation>
+    </message>
+    <message>
+        <source>Readonly Folder</source>
+        <translation>只讀資料夾</translation>
+    </message>
+    <message>
+        <source>Document</source>
+        <translation>檔案</translation>
+    </message>
+    <message>
+        <source>PDF Document</source>
+        <translation>PDF 檔案</translation>
+    </message>
+    <message>
+        <source>Image File</source>
+        <translation>圖像檔案</translation>
+    </message>
+    <message>
+        <source>Text Document</source>
+        <translation>文檔檔案</translation>
+    </message>
+    <message>
+        <source>Audio File</source>
+        <translation>音樂檔案</translation>
+    </message>
+    <message>
+        <source>Video File</source>
+        <translation>視頻檔案</translation>
+    </message>
+    <message>
+        <source>Word Document</source>
+        <translation>Word檔案</translation>
+    </message>
+    <message>
+        <source>PowerPoint Document</source>
+        <translation>PowerPoint檔案</translation>
+    </message>
+    <message>
+        <source>Excel Document</source>
+        <translation>Excel檔案</translation>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with system path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The path &quot;%1&quot; conflicts with an existing library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>uploading file list</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Folder is locked by another application</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>File is locked by another user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path is invalid</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error when indexing</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path ends with space or period character</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path contains invalid characters like &apos;|&apos; or &apos;:&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to open file cache database</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library name contains invalid characters such as &apos;:&apos;, &apos;*&apos;, &apos;|&apos;, &apos;?&apos;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Update to file denied by folder permission setting</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>%1 Client is already running</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in upload</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error occurred in download</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission denied on server. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Internal data corrupt on the client. Please try to resync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have write permission to the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not have permission to sync the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No permission to sync this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed all items from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Removed items older than days %1 from trash</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Published draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted draft</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updated file</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Moved folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Renamed library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Deleted library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Restored library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Updates in read-only library will not be uploaded</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReliablePostFileTask</name>
+    <message>
+        <source>File does not exist</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoDetailDialog</name>
+    <message>
+        <source>Library &quot;%1&quot;</source>
+        <translation>資料庫 %1</translation>
+    </message>
+    <message>
+        <source>This library is not downloaded yet</source>
+        <translation>此資料庫還沒有被下載</translation>
+    </message>
+    <message>
+        <source>Error: </source>
+        <translation>錯誤:</translation>
+    </message>
+    <message>
+        <source>every %1 seconds</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>RepoIcon</source>
+        <translation>資料庫圖示</translation>
+    </message>
+    <message>
+        <source>RepoName</source>
+        <translation>資料庫名稱</translation>
+    </message>
+    <message>
+        <source>TextLabel</source>
+        <translation>文本標簽:</translation>
+    </message>
+    <message>
+        <source>Owner:</source>
+        <translation>所有者:</translation>
+    </message>
+    <message>
+        <source>Last Modified:</source>
+        <translation>最後修改日期:</translation>
+    </message>
+    <message>
+        <source>mtime</source>
+        <translation>最後修改日期</translation>
+    </message>
+    <message>
+        <source>Size:</source>
+        <translation>檔案大小:</translation>
+    </message>
+    <message>
+        <source>Local Path:</source>
+        <translation>本地路徑:</translation>
+    </message>
+    <message>
+        <source>Status:</source>
+        <translation>狀態:</translation>
+    </message>
+    <message>
+        <source>RepoStatus</source>
+        <translation>資料庫狀態:</translation>
+    </message>
+    <message>
+        <source>Name:</source>
+        <translation>名稱:</translation>
+    </message>
+    <message>
+        <source>Sync Interval:</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>關閉</translation>
+    </message>
+</context>
+<context>
+    <name>RepoItemDelegate</name>
+    <message>
+        <source>, %1%2</source>
+        <translation>, %1%2</translation>
+    </message>
+    <message>
+        <source>, %1</source>
+        <translation>, %1</translation>
+    </message>
+    <message>
+        <source>This library has not been downloaded</source>
+        <translation>此資料庫還沒有被下載</translation>
+    </message>
+</context>
+<context>
+    <name>RepoService</name>
+    <message>
+        <source>Unable to open file &quot;%1&quot; from nonexistent library &quot;%2&quot;</source>
+        <translation>無法打開不存在資料庫 &quot;%2&quot; 中的文件 &quot;%1&quot;</translation>
+    </message>
+</context>
+<context>
+    <name>RepoTreeModel</name>
+    <message>
+        <source>Recently Updated</source>
+        <translation>最近更新</translation>
+    </message>
+    <message>
+        <source>My Libraries</source>
+        <translation>我的資料庫</translation>
+    </message>
+    <message>
+        <source>Sub Libraries</source>
+        <translation>子資料庫</translation>
+    </message>
+    <message>
+        <source>Shared with me</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with all</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Shared with groups</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Synced Libraries</source>
+        <translation>已同步資料庫</translation>
+    </message>
+    <message>
+        <source>sync initializing</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>RepoTreeView</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>關閉自動同步</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>開啓自動同步</translation>
+    </message>
+    <message>
+        <source>Show &amp;details</source>
+        <translation>顯示資料 (&amp;D) </translation>
+    </message>
+    <message>
+        <source>Show details of this library</source>
+        <translation>顯示此資料庫的檔案</translation>
+    </message>
+    <message>
+        <source>&amp;Sync this library</source>
+        <translation>同步此資料庫 (&amp;S)</translation>
+    </message>
+    <message>
+        <source>Sync this library</source>
+        <translation>同步此資料庫</translation>
+    </message>
+    <message>
+        <source>Recently Updated</source>
+        <translation>最近更新</translation>
+    </message>
+    <message>
+        <source>Sync &amp;now</source>
+        <translation>立即同步 (&amp;N) </translation>
+    </message>
+    <message>
+        <source>Sync this library immediately</source>
+        <translation>立即同步此資料庫</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel download</source>
+        <translation>取消下載(&amp;C)</translation>
+    </message>
+    <message>
+        <source>Cancel download of this library</source>
+        <translation>取消下載此資料庫</translation>
+    </message>
+    <message>
+        <source>&amp;Open folder</source>
+        <translation>開啟此資料夾(&amp;O)</translation>
+    </message>
+    <message>
+        <source>open local folder</source>
+        <translation>開啟本地資料夾</translation>
+    </message>
+    <message>
+        <source>&amp;Open local folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Unsync</source>
+        <translation>取消同步(&amp;U)</translation>
+    </message>
+    <message>
+        <source>unsync this library</source>
+        <translation>取消同步此資料庫</translation>
+    </message>
+    <message>
+        <source>&amp;View on cloud</source>
+        <translation>在瀏覽器中檢視(&amp;V)</translation>
+    </message>
+    <message>
+        <source>view this library on seahub</source>
+        <translation>在瀏覽器中檢視此資料庫</translation>
+    </message>
+    <message>
+        <source>Share to user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a user</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share to group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Share this library to a group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Open cloud file browser</source>
+        <translation>開啟雲端檔案瀏覽器</translation>
+    </message>
+    <message>
+        <source>open this library in embedded Cloud File Browser</source>
+        <translation>用內置的雲端檔案瀏覽器檢視此資料庫</translation>
+    </message>
+    <message>
+        <source>&amp;Leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>leave share</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;Resync this library</source>
+        <translation>重新同步(&amp;R)</translation>
+    </message>
+    <message>
+        <source>unsync and resync this library</source>
+        <translation>取消同步此資料庫然後重新開啟同步</translation>
+    </message>
+    <message>
+        <source>Set sync &amp;Interval</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>set sync interval for this library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to unsync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to resync the library &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Are you sure to overwrite the file &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to unsync library &quot;%1&quot;</source>
+        <translation>無法取消同步資料庫 %1</translation>
+    </message>
+    <message>
+        <source>Are you sure you want to leave the share &quot;%1&quot;?</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Leaving share failed</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to cancel this task:
+
+ %1</source>
+        <translation>無法取消這項任務:
+
+%1</translation>
+    </message>
+    <message>
+        <source>The download has been canceled</source>
+        <translation>下載已被取消</translation>
+    </message>
+    <message>
+        <source>You do not have permission to upload to this folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Unable to overwrite file &quot;%1&quot; with itself</source>
+        <translation>無法刪除用文件 &quot;%1&quot; 覆蓋自身</translation>
+    </message>
+    <message>
+        <source>Unable to delete file &quot;%1&quot;</source>
+        <translation>無法刪除檔案 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Failed to upload file: %1</source>
+        <translation>無法上傳檔案 &quot;%1&quot;</translation>
+    </message>
+    <message>
+        <source>Sync Interval (In seconds):</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Set Sync Internval For Library &quot;%1&quot;</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ReposTab</name>
+    <message>
+        <source>Search libraries</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation>重新嘗試</translation>
+    </message>
+    <message>
+        <source>Failed to get libraries information&lt;br/&gt;Please %1</source>
+        <translation>無法獲取資料庫檔案 &lt;br/&gt;
+請 %1</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApiClient</name>
+    <message>
+        <source>&lt;b&gt;Warning:&lt;/b&gt; The ssl certificate of this server is not trusted, proceed anyway?</source>
+        <translation>&lt;b&gt;警告:&lt;/b&gt; 伺服器的SSL證書不被信任,請問還需要繼續操作嗎?</translation>
+    </message>
+</context>
+<context>
+    <name>SeafileApplet</name>
+    <message>
+        <source>failed to add default account</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to initialize log: %s</source>
+        <translation>無法初始化日誌: %s</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to save client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to access %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>incorrect client id</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>failed to read %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileLinkDialog</name>
+    <message>
+        <source>%1 Internal Link</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>複製到剪貼簿</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>確認</translation>
+    </message>
+    <message>
+        <source>%1 Internal Link:</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileRpcClient</name>
+    <message>
+        <source>Unknown error</source>
+        <translation>遭遇未知錯誤</translation>
+    </message>
+    <message>
+        <source>internal error: failed to connect to daemon</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SeafileTrayIcon</name>
+    <message>
+        <source>Disable auto sync</source>
+        <translation>取消自動同步</translation>
+    </message>
+    <message>
+        <source>Enable auto sync</source>
+        <translation>開啓自動同步</translation>
+    </message>
+    <message>
+        <source>&amp;Quit</source>
+        <translation>退出(&amp;Q)</translation>
+    </message>
+    <message>
+        <source>Show main window</source>
+        <translation>顯示主界面</translation>
+    </message>
+    <message>
+        <source>Settings</source>
+        <translation>設定檔</translation>
+    </message>
+    <message>
+        <source>Open %1 &amp;folder</source>
+        <translation>開啟%1 資料夾(&amp;F)</translation>
+    </message>
+    <message>
+        <source>open %1 folder</source>
+        <translation>開啟%1的資料夾</translation>
+    </message>
+    <message>
+        <source>Open &amp;logs folder</source>
+        <translation>開啟日誌資料夾(&amp;l) </translation>
+    </message>
+    <message>
+        <source>Show file sync errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>&amp;About</source>
+        <translation>關於我們(&amp;A)</translation>
+    </message>
+    <message>
+        <source>Show the application&apos;s About box</source>
+        <translation>顯示應用程式的關於對話框</translation>
+    </message>
+    <message>
+        <source>&amp;Online help</source>
+        <translation>在線幫助(&amp;O)</translation>
+    </message>
+    <message>
+        <source>File</source>
+        <translation>檔案</translation>
+    </message>
+    <message>
+        <source>auto sync is disabled</source>
+        <translation>自動同步已被禁用</translation>
+    </message>
+    <message>
+        <source>Uploading</source>
+        <translation>正在上傳</translation>
+    </message>
+    <message>
+        <source>Downloading</source>
+        <translation>正在下載</translation>
+    </message>
+    <message>
+        <source>open %1 log folder</source>
+        <translation>開啟%1的日誌資料夾</translation>
+    </message>
+    <message>
+        <source>open %1 online help</source>
+        <translation>開啟%1的在線幫助</translation>
+    </message>
+    <message>
+        <source>some servers not connected</source>
+        <translation>到伺服器的連接部分運作中</translation>
+    </message>
+    <message>
+        <source>Upload log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>upload %1 log files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please login first</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Repair explorer extension</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Successfully fixed sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Faild to fix sync status icons for Explorer</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchResultListView</name>
+    <message>
+        <source>&amp;Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Show in folder</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SearchTab</name>
+    <message>
+        <source>Search files</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>retry</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to search&lt;br/&gt;Please %1</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>ServerStatusDialog</name>
+    <message>
+        <source>Servers connection status</source>
+        <translation>到伺服器連接狀態</translation>
+    </message>
+    <message>
+        <source>connected</source>
+        <translation>已連接</translation>
+    </message>
+    <message>
+        <source>disconnected</source>
+        <translation>已斷開</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>Close</source>
+        <translation>關閉</translation>
+    </message>
+</context>
+<context>
+    <name>SetRepoPasswordDialog</name>
+    <message>
+        <source>Please provide the library password</source>
+        <translation>請輸入資料庫的保護密碼</translation>
+    </message>
+    <message>
+        <source>Provide the password for library %1</source>
+        <translation>請輸入資料庫 %1 的保護密碼</translation>
+    </message>
+    <message>
+        <source>Please enter the password</source>
+        <translation>請輸入密碼</translation>
+    </message>
+    <message>
+        <source>Incorrect password</source>
+        <translation>無法理解的密碼</translation>
+    </message>
+    <message>
+        <source>Unknown error</source>
+        <translation>遭遇未知錯誤</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>確認</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Settings</source>
+        <translation>設定檔</translation>
+    </message>
+    <message>
+        <source>Auto start %1 after login</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Hide %1 Icon from the dock</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>None</source>
+        <translation>無代理</translation>
+    </message>
+    <message>
+        <source>HTTP Proxy</source>
+        <translation>HTTP 代理</translation>
+    </message>
+    <message>
+        <source>Socks5 Proxy</source>
+        <translation>SOCKS5 代理</translation>
+    </message>
+    <message>
+        <source>System Proxy</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>You have changed languange. Restart to apply it?</source>
+        <translation>您改變了使用的語言。現在重啓生效嗎?</translation>
+    </message>
+    <message>
+        <source>The proxy host address can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The proxy port is incorrect</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy username can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Proxy password can&apos;t be empty</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>Hide main window when started</source>
+        <translation>啟動時隱藏主界面</translation>
+    </message>
+    <message>
+        <source>Notify when libraries are synchronized</source>
+        <translation>當資料庫同步完成時提示</translation>
+    </message>
+    <message>
+        <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+        <translation>同步Microsoft Office 和Libreoffice的臨時檔案</translation>
+    </message>
+    <message>
+        <source>Download speed limit (KB/s):</source>
+        <translation>下載速率 (KB/s):</translation>
+    </message>
+    <message>
+        <source>Upload speed limit (KB/s):</source>
+        <translation>上載速率(KB/s):</translation>
+    </message>
+    <message>
+        <source>Basic</source>
+        <translation>基礎</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library</source>
+        <translation>禁止自動取消同步資料庫</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+        <translation>禁止當本地資料庫被刪除或無法訪問時,自動取消同步資料庫</translation>
+    </message>
+    <message>
+        <source>Do not unsync a library when not found on server</source>
+        <translation>禁止當資料庫無法在伺服器找到時,自動取消同步自理啊哭</translation>
+    </message>
+    <message>
+        <source>Do not automatically unsync a library when it&apos;s not found on server</source>
+        <translation>禁止當資料庫無法在伺服器找到時,自動取消同步自理啊哭</translation>
+    </message>
+    <message>
+        <source>Enable FinderSync Extension</source>
+        <translation>啟用 Finder的延伸功能</translation>
+    </message>
+    <message>
+        <source>Enable Explorer Extension</source>
+        <translation>啟用檔案瀏覽器的延伸功能</translation>
+    </message>
+    <message>
+        <source>Check for updates automatically</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Do not verify server certificate in HTTPS syncing</source>
+        <translation>在HTTPS 同步過程中無法認證伺服器的證書</translation>
+    </message>
+    <message>
+        <source>Enable syncing with an existing folder with a different name</source>
+        <translation>開啟與已存在的不同文件名的資料夾同步的選項</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>高級</translation>
+    </message>
+    <message>
+        <source>Language (need restart)</source>
+        <translation>語言 (需要重啓)</translation>
+    </message>
+    <message>
+        <source>Language</source>
+        <translation>語言</translation>
+    </message>
+    <message>
+        <source>Proxy Type:</source>
+        <translation>代理類型:</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>主機地址:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>端口:</translation>
+    </message>
+    <message>
+        <source>0</source>
+        <translation>0</translation>
+    </message>
+    <message>
+        <source>Username:</source>
+        <translation>用戶名:</translation>
+    </message>
+    <message>
+        <source>Password:</source>
+        <translation>密碼:</translation>
+    </message>
+    <message>
+        <source>Proxy server requires a password</source>
+        <translation>代理伺服器需要密碼</translation>
+    </message>
+    <message>
+        <source>Network</source>
+        <translation>網路</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>確認</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>取消</translation>
+    </message>
+</context>
+<context>
+    <name>SharedItemDelegate</name>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remove Share</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedItemsTableModel</name>
+    <message>
+        <source>Click to edit</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Created by %1</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Write</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Read Only</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Group</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>User</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Permission</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>The previous operation is still in progres</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SharedLinkDialog</name>
+    <message>
+        <source>Share Link</source>
+        <translation>分享連接</translation>
+    </message>
+    <message>
+        <source>Share link:</source>
+        <translation>分享連接:</translation>
+    </message>
+    <message>
+        <source>Direct Download</source>
+        <translation>直接下載</translation>
+    </message>
+    <message>
+        <source>Copy to clipboard</source>
+        <translation>複製到剪貼簿</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>確認</translation>
+    </message>
+</context>
+<context>
+    <name>ShibLoginDialog</name>
+    <message>
+        <source>Login with Shibboleth</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Failed to save current account</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SslConfirmDialog</name>
+    <message>
+        <source>Untrusted Connection</source>
+        <translation>不被信任的連接</translation>
+    </message>
+    <message>
+        <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+        <translation>%1 使用了未認證的安全證書。此次連接可能是不安全的,請問還繼續嗎?</translation>
+    </message>
+    <message>
+        <source>Current RSA key fingerprint is %1</source>
+        <translation>目前證書 RSA 指紋是 %1</translation>
+    </message>
+    <message>
+        <source>Previous RSA key fingerprint is %1</source>
+        <translation>先前證書 RSA 指紋是 %1</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>Remember my choice</source>
+        <translation>記住我的選項</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>好</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>不好</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesListView</name>
+    <message>
+        <source>&amp;Open</source>
+        <translation>開啟(&amp;O)</translation>
+    </message>
+    <message>
+        <source>Open this file</source>
+        <translation>開啟此檔案</translation>
+    </message>
+    <message>
+        <source>view on &amp;Web</source>
+        <translation>在瀏覽器中檢視(&amp;W)</translation>
+    </message>
+    <message>
+        <source>view this file on website</source>
+        <translation>在瀏覽器中檢視此檔案</translation>
+    </message>
+</context>
+<context>
+    <name>StarredFilesTab</name>
+    <message>
+        <source>retry</source>
+        <translation>重新嘗試</translation>
+    </message>
+    <message>
+        <source>Failed to get starred files information&lt;br/&gt;Please %1</source>
+        <translation>無法獲取標示檔案的訊息&lt;br/&gt;請 %1</translation>
+    </message>
+    <message>
+        <source>You have no starred files yet.</source>
+        <translation>您沒有標示任何檔案</translation>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsDialog</name>
+    <message>
+        <source>File Sync Errors</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>No sync errors.</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>SyncErrorsTableModel</name>
+    <message>
+        <source>Double click to open the library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Library</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Path</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Time</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>TwoFactorDialog</name>
+    <message>
+        <source>Enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Two Factor Authentication</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Please enter the two factor authentication token</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>mText</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Remember this device</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="unfinished"/>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="unfinished"/>
+    </message>
+</context>
+<context>
+    <name>UninstallHelperDialog</name>
+    <message>
+        <source>Uninstall %1</source>
+        <translation>移除 %1</translation>
+    </message>
+    <message>
+        <source>Do you want to remove the %1 account information?</source>
+        <translation>您想刪除 帳號 %1 的訊息?</translation>
+    </message>
+    <message>
+        <source>Removing account information...</source>
+        <translation>正在刪除帳號訊息...</translation>
+    </message>
+    <message>
+        <source>Dialog</source>
+        <translation>對話框</translation>
+    </message>
+    <message>
+        <source>text</source>
+        <translation>文本</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <translation>好</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <translation>不好</translation>
+    </message>
+</context>
+</TS>
\ No newline at end of file
diff --git a/images/account-256.png b/images/account-256.png
new file mode 100644 (file)
index 0000000..9ad9499
Binary files /dev/null and b/images/account-256.png differ
diff --git a/images/account-checked.png b/images/account-checked.png
new file mode 100644 (file)
index 0000000..0aedca2
Binary files /dev/null and b/images/account-checked.png differ
diff --git a/images/account-checked@2x.png b/images/account-checked@2x.png
new file mode 100644 (file)
index 0000000..88d7315
Binary files /dev/null and b/images/account-checked@2x.png differ
diff --git a/images/account-else.png b/images/account-else.png
new file mode 100644 (file)
index 0000000..5a7d93f
Binary files /dev/null and b/images/account-else.png differ
diff --git a/images/account-else@2x.png b/images/account-else@2x.png
new file mode 100644 (file)
index 0000000..5a7d93f
Binary files /dev/null and b/images/account-else@2x.png differ
diff --git a/images/account-settings.png b/images/account-settings.png
new file mode 100644 (file)
index 0000000..3188ec8
Binary files /dev/null and b/images/account-settings.png differ
diff --git a/images/account-settings@2x.png b/images/account-settings@2x.png
new file mode 100644 (file)
index 0000000..50cc69d
Binary files /dev/null and b/images/account-settings@2x.png differ
diff --git a/images/account.png b/images/account.png
new file mode 100644 (file)
index 0000000..70a8ca5
Binary files /dev/null and b/images/account.png differ
diff --git a/images/account@2x.png b/images/account@2x.png
new file mode 100644 (file)
index 0000000..ee6aa6a
Binary files /dev/null and b/images/account@2x.png differ
diff --git a/images/add-account.png b/images/add-account.png
new file mode 100644 (file)
index 0000000..dbb22e3
Binary files /dev/null and b/images/add-account.png differ
diff --git a/images/add-account@2x.png b/images/add-account@2x.png
new file mode 100644 (file)
index 0000000..a00b208
Binary files /dev/null and b/images/add-account@2x.png differ
diff --git a/images/cancel.png b/images/cancel.png
new file mode 100644 (file)
index 0000000..648ba9c
Binary files /dev/null and b/images/cancel.png differ
diff --git a/images/cancel@2x.png b/images/cancel@2x.png
new file mode 100644 (file)
index 0000000..3e495d8
Binary files /dev/null and b/images/cancel@2x.png differ
diff --git a/images/clock.png b/images/clock.png
new file mode 100644 (file)
index 0000000..6b03bdc
Binary files /dev/null and b/images/clock.png differ
diff --git a/images/clock@2x.png b/images/clock@2x.png
new file mode 100644 (file)
index 0000000..4795ea8
Binary files /dev/null and b/images/clock@2x.png differ
diff --git a/images/cloud-gray.png b/images/cloud-gray.png
new file mode 100644 (file)
index 0000000..f2f2e1e
Binary files /dev/null and b/images/cloud-gray.png differ
diff --git a/images/cloud-gray@2x.png b/images/cloud-gray@2x.png
new file mode 100644 (file)
index 0000000..125d882
Binary files /dev/null and b/images/cloud-gray@2x.png differ
diff --git a/images/daemon_down.png b/images/daemon_down.png
new file mode 100644 (file)
index 0000000..0661ba5
Binary files /dev/null and b/images/daemon_down.png differ
diff --git a/images/daemon_up.png b/images/daemon_up.png
new file mode 100644 (file)
index 0000000..933630d
Binary files /dev/null and b/images/daemon_up.png differ
diff --git a/images/delete-account.png b/images/delete-account.png
new file mode 100644 (file)
index 0000000..4383533
Binary files /dev/null and b/images/delete-account.png differ
diff --git a/images/delete-account@2x.png b/images/delete-account@2x.png
new file mode 100644 (file)
index 0000000..32d5431
Binary files /dev/null and b/images/delete-account@2x.png differ
diff --git a/images/disk@2x.png b/images/disk@2x.png
new file mode 100644 (file)
index 0000000..23f520e
Binary files /dev/null and b/images/disk@2x.png differ
diff --git a/images/download-48.png b/images/download-48.png
new file mode 100644 (file)
index 0000000..43c05e5
Binary files /dev/null and b/images/download-48.png differ
diff --git a/images/filebrowser/add.png b/images/filebrowser/add.png
new file mode 100755 (executable)
index 0000000..6524d5b
Binary files /dev/null and b/images/filebrowser/add.png differ
diff --git a/images/filebrowser/add@2x.png b/images/filebrowser/add@2x.png
new file mode 100755 (executable)
index 0000000..443ea40
Binary files /dev/null and b/images/filebrowser/add@2x.png differ
diff --git a/images/filebrowser/backward.png b/images/filebrowser/backward.png
new file mode 100644 (file)
index 0000000..81e0545
Binary files /dev/null and b/images/filebrowser/backward.png differ
diff --git a/images/filebrowser/backward@2x.png b/images/filebrowser/backward@2x.png
new file mode 100644 (file)
index 0000000..62b23fc
Binary files /dev/null and b/images/filebrowser/backward@2x.png differ
diff --git a/images/filebrowser/down-arrow.png b/images/filebrowser/down-arrow.png
new file mode 100644 (file)
index 0000000..f3a551c
Binary files /dev/null and b/images/filebrowser/down-arrow.png differ
diff --git a/images/filebrowser/forward.png b/images/filebrowser/forward.png
new file mode 100644 (file)
index 0000000..abf3467
Binary files /dev/null and b/images/filebrowser/forward.png differ
diff --git a/images/filebrowser/forward@2x.png b/images/filebrowser/forward@2x.png
new file mode 100644 (file)
index 0000000..7494cb8
Binary files /dev/null and b/images/filebrowser/forward@2x.png differ
diff --git a/images/filebrowser/home.png b/images/filebrowser/home.png
new file mode 100755 (executable)
index 0000000..605144f
Binary files /dev/null and b/images/filebrowser/home.png differ
diff --git a/images/filebrowser/home@2x.png b/images/filebrowser/home@2x.png
new file mode 100755 (executable)
index 0000000..289adf5
Binary files /dev/null and b/images/filebrowser/home@2x.png differ
diff --git a/images/filebrowser/locked-by-me.png b/images/filebrowser/locked-by-me.png
new file mode 100755 (executable)
index 0000000..48b3bb1
Binary files /dev/null and b/images/filebrowser/locked-by-me.png differ
diff --git a/images/filebrowser/locked-by-me@2x.png b/images/filebrowser/locked-by-me@2x.png
new file mode 100755 (executable)
index 0000000..e820e65
Binary files /dev/null and b/images/filebrowser/locked-by-me@2x.png differ
diff --git a/images/filebrowser/locked.png b/images/filebrowser/locked.png
new file mode 100755 (executable)
index 0000000..8a0672b
Binary files /dev/null and b/images/filebrowser/locked.png differ
diff --git a/images/filebrowser/locked@2x.png b/images/filebrowser/locked@2x.png
new file mode 100755 (executable)
index 0000000..9347372
Binary files /dev/null and b/images/filebrowser/locked@2x.png differ
diff --git a/images/filebrowser/path-separator.png b/images/filebrowser/path-separator.png
new file mode 100755 (executable)
index 0000000..1dff1f5
Binary files /dev/null and b/images/filebrowser/path-separator.png differ
diff --git a/images/filebrowser/path-separator@2x.png b/images/filebrowser/path-separator@2x.png
new file mode 100755 (executable)
index 0000000..f1cb87c
Binary files /dev/null and b/images/filebrowser/path-separator@2x.png differ
diff --git a/images/filebrowser/refresh-gray.png b/images/filebrowser/refresh-gray.png
new file mode 100755 (executable)
index 0000000..32a64fe
Binary files /dev/null and b/images/filebrowser/refresh-gray.png differ
diff --git a/images/filebrowser/refresh-gray@2x.png b/images/filebrowser/refresh-gray@2x.png
new file mode 100755 (executable)
index 0000000..2a2a8f5
Binary files /dev/null and b/images/filebrowser/refresh-gray@2x.png differ
diff --git a/images/filebrowser/settings.png b/images/filebrowser/settings.png
new file mode 100644 (file)
index 0000000..3188ec8
Binary files /dev/null and b/images/filebrowser/settings.png differ
diff --git a/images/filebrowser/settings@2x.png b/images/filebrowser/settings@2x.png
new file mode 100644 (file)
index 0000000..50cc69d
Binary files /dev/null and b/images/filebrowser/settings@2x.png differ
diff --git a/images/filebrowser/up-arrow.png b/images/filebrowser/up-arrow.png
new file mode 100644 (file)
index 0000000..59c9ae3
Binary files /dev/null and b/images/filebrowser/up-arrow.png differ
diff --git a/images/files/file_audio.png b/images/files/file_audio.png
new file mode 100644 (file)
index 0000000..f5a6234
Binary files /dev/null and b/images/files/file_audio.png differ
diff --git a/images/files/file_audio@2x.png b/images/files/file_audio@2x.png
new file mode 100644 (file)
index 0000000..eb1a352
Binary files /dev/null and b/images/files/file_audio@2x.png differ
diff --git a/images/files/file_folder.png b/images/files/file_folder.png
new file mode 100644 (file)
index 0000000..bccc103
Binary files /dev/null and b/images/files/file_folder.png differ
diff --git a/images/files/file_folder@2x.png b/images/files/file_folder@2x.png
new file mode 100644 (file)
index 0000000..460ae31
Binary files /dev/null and b/images/files/file_folder@2x.png differ
diff --git a/images/files/file_folder_readonly.png b/images/files/file_folder_readonly.png
new file mode 100644 (file)
index 0000000..866a249
Binary files /dev/null and b/images/files/file_folder_readonly.png differ
diff --git a/images/files/file_folder_readonly@2x.png b/images/files/file_folder_readonly@2x.png
new file mode 100644 (file)
index 0000000..25af215
Binary files /dev/null and b/images/files/file_folder_readonly@2x.png differ
diff --git a/images/files/file_image.png b/images/files/file_image.png
new file mode 100644 (file)
index 0000000..2b4494f
Binary files /dev/null and b/images/files/file_image.png differ
diff --git a/images/files/file_image@2x.png b/images/files/file_image@2x.png
new file mode 100644 (file)
index 0000000..1b7c34e
Binary files /dev/null and b/images/files/file_image@2x.png differ
diff --git a/images/files/file_ms_excel.png b/images/files/file_ms_excel.png
new file mode 100644 (file)
index 0000000..3756588
Binary files /dev/null and b/images/files/file_ms_excel.png differ
diff --git a/images/files/file_ms_excel@2x.png b/images/files/file_ms_excel@2x.png
new file mode 100644 (file)
index 0000000..994f698
Binary files /dev/null and b/images/files/file_ms_excel@2x.png differ
diff --git a/images/files/file_ms_ppt.png b/images/files/file_ms_ppt.png
new file mode 100644 (file)
index 0000000..e51d4c9
Binary files /dev/null and b/images/files/file_ms_ppt.png differ
diff --git a/images/files/file_ms_ppt@2x.png b/images/files/file_ms_ppt@2x.png
new file mode 100644 (file)
index 0000000..c46eee5
Binary files /dev/null and b/images/files/file_ms_ppt@2x.png differ
diff --git a/images/files/file_ms_word.png b/images/files/file_ms_word.png
new file mode 100644 (file)
index 0000000..ef36873
Binary files /dev/null and b/images/files/file_ms_word.png differ
diff --git a/images/files/file_ms_word@2x.png b/images/files/file_ms_word@2x.png
new file mode 100644 (file)
index 0000000..c772f74
Binary files /dev/null and b/images/files/file_ms_word@2x.png differ
diff --git a/images/files/file_pdf.png b/images/files/file_pdf.png
new file mode 100644 (file)
index 0000000..9789042
Binary files /dev/null and b/images/files/file_pdf.png differ
diff --git a/images/files/file_pdf@2x.png b/images/files/file_pdf@2x.png
new file mode 100644 (file)
index 0000000..43af1cb
Binary files /dev/null and b/images/files/file_pdf@2x.png differ
diff --git a/images/files/file_text.png b/images/files/file_text.png
new file mode 100644 (file)
index 0000000..ef36873
Binary files /dev/null and b/images/files/file_text.png differ
diff --git a/images/files/file_text@2x.png b/images/files/file_text@2x.png
new file mode 100644 (file)
index 0000000..c772f74
Binary files /dev/null and b/images/files/file_text@2x.png differ
diff --git a/images/files/file_unknown.png b/images/files/file_unknown.png
new file mode 100644 (file)
index 0000000..78ff664
Binary files /dev/null and b/images/files/file_unknown.png differ
diff --git a/images/files/file_unknown@2x.png b/images/files/file_unknown@2x.png
new file mode 100644 (file)
index 0000000..ad6f645
Binary files /dev/null and b/images/files/file_unknown@2x.png differ
diff --git a/images/files/file_video.png b/images/files/file_video.png
new file mode 100644 (file)
index 0000000..40d526e
Binary files /dev/null and b/images/files/file_video.png differ
diff --git a/images/files/file_video@2x.png b/images/files/file_video@2x.png
new file mode 100644 (file)
index 0000000..04f1879
Binary files /dev/null and b/images/files/file_video@2x.png differ
diff --git a/images/files/file_zip.png b/images/files/file_zip.png
new file mode 100644 (file)
index 0000000..9f2df73
Binary files /dev/null and b/images/files/file_zip.png differ
diff --git a/images/files/file_zip@2x.png b/images/files/file_zip@2x.png
new file mode 100644 (file)
index 0000000..16a5f69
Binary files /dev/null and b/images/files/file_zip@2x.png differ
diff --git a/images/files_v2/file_audio.png b/images/files_v2/file_audio.png
new file mode 100644 (file)
index 0000000..8cad88c
Binary files /dev/null and b/images/files_v2/file_audio.png differ
diff --git a/images/files_v2/file_audio@2x.png b/images/files_v2/file_audio@2x.png
new file mode 100755 (executable)
index 0000000..05416f1
Binary files /dev/null and b/images/files_v2/file_audio@2x.png differ
diff --git a/images/files_v2/file_folder.png b/images/files_v2/file_folder.png
new file mode 100644 (file)
index 0000000..d3b467c
Binary files /dev/null and b/images/files_v2/file_folder.png differ
diff --git a/images/files_v2/file_folder@2x.png b/images/files_v2/file_folder@2x.png
new file mode 100755 (executable)
index 0000000..22e15da
Binary files /dev/null and b/images/files_v2/file_folder@2x.png differ
diff --git a/images/files_v2/file_folder_readonly.png b/images/files_v2/file_folder_readonly.png
new file mode 100755 (executable)
index 0000000..466176e
Binary files /dev/null and b/images/files_v2/file_folder_readonly.png differ
diff --git a/images/files_v2/file_folder_readonly@2x.png b/images/files_v2/file_folder_readonly@2x.png
new file mode 100755 (executable)
index 0000000..65ee3d7
Binary files /dev/null and b/images/files_v2/file_folder_readonly@2x.png differ
diff --git a/images/files_v2/file_image.png b/images/files_v2/file_image.png
new file mode 100644 (file)
index 0000000..eacc702
Binary files /dev/null and b/images/files_v2/file_image.png differ
diff --git a/images/files_v2/file_image@2x.png b/images/files_v2/file_image@2x.png
new file mode 100755 (executable)
index 0000000..8b453ba
Binary files /dev/null and b/images/files_v2/file_image@2x.png differ
diff --git a/images/files_v2/file_ms_excel.png b/images/files_v2/file_ms_excel.png
new file mode 100644 (file)
index 0000000..a6895ec
Binary files /dev/null and b/images/files_v2/file_ms_excel.png differ
diff --git a/images/files_v2/file_ms_excel@2x.png b/images/files_v2/file_ms_excel@2x.png
new file mode 100755 (executable)
index 0000000..9efa520
Binary files /dev/null and b/images/files_v2/file_ms_excel@2x.png differ
diff --git a/images/files_v2/file_ms_ppt.png b/images/files_v2/file_ms_ppt.png
new file mode 100644 (file)
index 0000000..3a6626e
Binary files /dev/null and b/images/files_v2/file_ms_ppt.png differ
diff --git a/images/files_v2/file_ms_ppt@2x.png b/images/files_v2/file_ms_ppt@2x.png
new file mode 100755 (executable)
index 0000000..fd4f81d
Binary files /dev/null and b/images/files_v2/file_ms_ppt@2x.png differ
diff --git a/images/files_v2/file_ms_word.png b/images/files_v2/file_ms_word.png
new file mode 100644 (file)
index 0000000..7585c3f
Binary files /dev/null and b/images/files_v2/file_ms_word.png differ
diff --git a/images/files_v2/file_ms_word@2x.png b/images/files_v2/file_ms_word@2x.png
new file mode 100755 (executable)
index 0000000..ed71717
Binary files /dev/null and b/images/files_v2/file_ms_word@2x.png differ
diff --git a/images/files_v2/file_pdf.png b/images/files_v2/file_pdf.png
new file mode 100644 (file)
index 0000000..6347c66
Binary files /dev/null and b/images/files_v2/file_pdf.png differ
diff --git a/images/files_v2/file_pdf@2x.png b/images/files_v2/file_pdf@2x.png
new file mode 100755 (executable)
index 0000000..9ffe469
Binary files /dev/null and b/images/files_v2/file_pdf@2x.png differ
diff --git a/images/files_v2/file_text.png b/images/files_v2/file_text.png
new file mode 100644 (file)
index 0000000..d73dc7c
Binary files /dev/null and b/images/files_v2/file_text.png differ
diff --git a/images/files_v2/file_text@2x.png b/images/files_v2/file_text@2x.png
new file mode 100755 (executable)
index 0000000..e9adbfc
Binary files /dev/null and b/images/files_v2/file_text@2x.png differ
diff --git a/images/files_v2/file_unknown.png b/images/files_v2/file_unknown.png
new file mode 100644 (file)
index 0000000..0d8ed6f
Binary files /dev/null and b/images/files_v2/file_unknown.png differ
diff --git a/images/files_v2/file_unknown@2x.png b/images/files_v2/file_unknown@2x.png
new file mode 100755 (executable)
index 0000000..e8c8906
Binary files /dev/null and b/images/files_v2/file_unknown@2x.png differ
diff --git a/images/files_v2/file_video.png b/images/files_v2/file_video.png
new file mode 100644 (file)
index 0000000..1d27c45
Binary files /dev/null and b/images/files_v2/file_video.png differ
diff --git a/images/files_v2/file_video@2x.png b/images/files_v2/file_video@2x.png
new file mode 100755 (executable)
index 0000000..413d526
Binary files /dev/null and b/images/files_v2/file_video@2x.png differ
diff --git a/images/files_v2/file_zip.png b/images/files_v2/file_zip.png
new file mode 100644 (file)
index 0000000..1bfcb31
Binary files /dev/null and b/images/files_v2/file_zip.png differ
diff --git a/images/files_v2/file_zip@2x.png b/images/files_v2/file_zip@2x.png
new file mode 100644 (file)
index 0000000..f3f62ff
Binary files /dev/null and b/images/files_v2/file_zip@2x.png differ
diff --git a/images/folder.png b/images/folder.png
new file mode 100644 (file)
index 0000000..f7c06a4
Binary files /dev/null and b/images/folder.png differ
diff --git a/images/info-gray.png b/images/info-gray.png
new file mode 100644 (file)
index 0000000..d9b5e2f
Binary files /dev/null and b/images/info-gray.png differ
diff --git a/images/info-gray@2x.png b/images/info-gray@2x.png
new file mode 100644 (file)
index 0000000..5d7ade0
Binary files /dev/null and b/images/info-gray@2x.png differ
diff --git a/images/info.png b/images/info.png
new file mode 100644 (file)
index 0000000..8a86f3c
Binary files /dev/null and b/images/info.png differ
diff --git a/images/leave-share.png b/images/leave-share.png
new file mode 100644 (file)
index 0000000..4383533
Binary files /dev/null and b/images/leave-share.png differ
diff --git a/images/leave-share@2x.png b/images/leave-share@2x.png
new file mode 100644 (file)
index 0000000..32d5431
Binary files /dev/null and b/images/leave-share@2x.png differ
diff --git a/images/library-256.png b/images/library-256.png
new file mode 100644 (file)
index 0000000..483a4f4
Binary files /dev/null and b/images/library-256.png differ
diff --git a/images/loading-spinner.gif b/images/loading-spinner.gif
new file mode 100755 (executable)
index 0000000..1c72ebb
Binary files /dev/null and b/images/loading-spinner.gif differ
diff --git a/images/logout.png b/images/logout.png
new file mode 100644 (file)
index 0000000..4594a2c
Binary files /dev/null and b/images/logout.png differ
diff --git a/images/logout@2x.png b/images/logout@2x.png
new file mode 100644 (file)
index 0000000..b04f0ba
Binary files /dev/null and b/images/logout@2x.png differ
diff --git a/images/mac/daemon_down.png b/images/mac/daemon_down.png
new file mode 100644 (file)
index 0000000..e8b4d67
Binary files /dev/null and b/images/mac/daemon_down.png differ
diff --git a/images/mac/daemon_down@2x.png b/images/mac/daemon_down@2x.png
new file mode 100644 (file)
index 0000000..76fd9d8
Binary files /dev/null and b/images/mac/daemon_down@2x.png differ
diff --git a/images/mac/daemon_down_white.png b/images/mac/daemon_down_white.png
new file mode 100644 (file)
index 0000000..41cff37
Binary files /dev/null and b/images/mac/daemon_down_white.png differ
diff --git a/images/mac/daemon_down_white@2x.png b/images/mac/daemon_down_white@2x.png
new file mode 100644 (file)
index 0000000..bc69f1d
Binary files /dev/null and b/images/mac/daemon_down_white@2x.png differ
diff --git a/images/mac/daemon_up.png b/images/mac/daemon_up.png
new file mode 100644 (file)
index 0000000..d84dcef
Binary files /dev/null and b/images/mac/daemon_up.png differ
diff --git a/images/mac/daemon_up@2x.png b/images/mac/daemon_up@2x.png
new file mode 100644 (file)
index 0000000..2129240
Binary files /dev/null and b/images/mac/daemon_up@2x.png differ
diff --git a/images/mac/daemon_up_white.png b/images/mac/daemon_up_white.png
new file mode 100644 (file)
index 0000000..e4e5df3
Binary files /dev/null and b/images/mac/daemon_up_white.png differ
diff --git a/images/mac/daemon_up_white@2x.png b/images/mac/daemon_up_white@2x.png
new file mode 100644 (file)
index 0000000..2ec1352
Binary files /dev/null and b/images/mac/daemon_up_white@2x.png differ
diff --git a/images/mac/notification.png b/images/mac/notification.png
new file mode 100644 (file)
index 0000000..f648a2d
Binary files /dev/null and b/images/mac/notification.png differ
diff --git a/images/mac/notification@2x.png b/images/mac/notification@2x.png
new file mode 100644 (file)
index 0000000..306557c
Binary files /dev/null and b/images/mac/notification@2x.png differ
diff --git a/images/mac/notification_white.png b/images/mac/notification_white.png
new file mode 100644 (file)
index 0000000..98595af
Binary files /dev/null and b/images/mac/notification_white.png differ
diff --git a/images/mac/seafile_auto_sync_disabled.png b/images/mac/seafile_auto_sync_disabled.png
new file mode 100644 (file)
index 0000000..9a4b903
Binary files /dev/null and b/images/mac/seafile_auto_sync_disabled.png differ
diff --git a/images/mac/seafile_auto_sync_disabled@2x.png b/images/mac/seafile_auto_sync_disabled@2x.png
new file mode 100644 (file)
index 0000000..55306be
Binary files /dev/null and b/images/mac/seafile_auto_sync_disabled@2x.png differ
diff --git a/images/mac/seafile_auto_sync_disabled_white.png b/images/mac/seafile_auto_sync_disabled_white.png
new file mode 100644 (file)
index 0000000..d0977cc
Binary files /dev/null and b/images/mac/seafile_auto_sync_disabled_white.png differ
diff --git a/images/mac/seafile_auto_sync_disabled_white@2x.png b/images/mac/seafile_auto_sync_disabled_white@2x.png
new file mode 100644 (file)
index 0000000..76e4e60
Binary files /dev/null and b/images/mac/seafile_auto_sync_disabled_white@2x.png differ
diff --git a/images/mac/seafile_transfer_1.png b/images/mac/seafile_transfer_1.png
new file mode 100644 (file)
index 0000000..e1228f7
Binary files /dev/null and b/images/mac/seafile_transfer_1.png differ
diff --git a/images/mac/seafile_transfer_1_white.png b/images/mac/seafile_transfer_1_white.png
new file mode 100644 (file)
index 0000000..58dee75
Binary files /dev/null and b/images/mac/seafile_transfer_1_white.png differ
diff --git a/images/mac/seafile_transfer_2.png b/images/mac/seafile_transfer_2.png
new file mode 100644 (file)
index 0000000..082ac0b
Binary files /dev/null and b/images/mac/seafile_transfer_2.png differ
diff --git a/images/mac/seafile_transfer_2_white.png b/images/mac/seafile_transfer_2_white.png
new file mode 100644 (file)
index 0000000..0af5bda
Binary files /dev/null and b/images/mac/seafile_transfer_2_white.png differ
diff --git a/images/mac/seafile_warning.png b/images/mac/seafile_warning.png
new file mode 100644 (file)
index 0000000..b613f07
Binary files /dev/null and b/images/mac/seafile_warning.png differ
diff --git a/images/mac/seafile_warning@2x.png b/images/mac/seafile_warning@2x.png
new file mode 100644 (file)
index 0000000..638fc9c
Binary files /dev/null and b/images/mac/seafile_warning@2x.png differ
diff --git a/images/mac/seafile_warning_white.png b/images/mac/seafile_warning_white.png
new file mode 100644 (file)
index 0000000..c24b1b4
Binary files /dev/null and b/images/mac/seafile_warning_white.png differ
diff --git a/images/mac/seafile_warning_white@2x.png b/images/mac/seafile_warning_white@2x.png
new file mode 100644 (file)
index 0000000..57a8563
Binary files /dev/null and b/images/mac/seafile_warning_white@2x.png differ
diff --git a/images/main-panel/download.png b/images/main-panel/download.png
new file mode 100644 (file)
index 0000000..d3825f7
Binary files /dev/null and b/images/main-panel/download.png differ
diff --git a/images/main-panel/download@2x.png b/images/main-panel/download@2x.png
new file mode 100644 (file)
index 0000000..889f189
Binary files /dev/null and b/images/main-panel/download@2x.png differ
diff --git a/images/main-panel/folder.png b/images/main-panel/folder.png
new file mode 100644 (file)
index 0000000..cd50dfc
Binary files /dev/null and b/images/main-panel/folder.png differ
diff --git a/images/main-panel/folder@2x.png b/images/main-panel/folder@2x.png
new file mode 100644 (file)
index 0000000..638ee16
Binary files /dev/null and b/images/main-panel/folder@2x.png differ
diff --git a/images/main-panel/library-encrypted.png b/images/main-panel/library-encrypted.png
new file mode 100644 (file)
index 0000000..df76c65
Binary files /dev/null and b/images/main-panel/library-encrypted.png differ
diff --git a/images/main-panel/library-encrypted@2x.png b/images/main-panel/library-encrypted@2x.png
new file mode 100644 (file)
index 0000000..291551b
Binary files /dev/null and b/images/main-panel/library-encrypted@2x.png differ
diff --git a/images/main-panel/library-normal.png b/images/main-panel/library-normal.png
new file mode 100644 (file)
index 0000000..494cbf9
Binary files /dev/null and b/images/main-panel/library-normal.png differ
diff --git a/images/main-panel/library-normal@2x.png b/images/main-panel/library-normal@2x.png
new file mode 100644 (file)
index 0000000..b707083
Binary files /dev/null and b/images/main-panel/library-normal@2x.png differ
diff --git a/images/main-panel/library-readonly.png b/images/main-panel/library-readonly.png
new file mode 100644 (file)
index 0000000..b590040
Binary files /dev/null and b/images/main-panel/library-readonly.png differ
diff --git a/images/main-panel/library-readonly@2x.png b/images/main-panel/library-readonly@2x.png
new file mode 100644 (file)
index 0000000..efaa7f1
Binary files /dev/null and b/images/main-panel/library-readonly@2x.png differ
diff --git a/images/main-panel/network-error.png b/images/main-panel/network-error.png
new file mode 100644 (file)
index 0000000..843364e
Binary files /dev/null and b/images/main-panel/network-error.png differ
diff --git a/images/main-panel/network-error@2x.png b/images/main-panel/network-error@2x.png
new file mode 100644 (file)
index 0000000..e5ff09e
Binary files /dev/null and b/images/main-panel/network-error@2x.png differ
diff --git a/images/main-panel/search-background.png b/images/main-panel/search-background.png
new file mode 100644 (file)
index 0000000..68842e6
Binary files /dev/null and b/images/main-panel/search-background.png differ
diff --git a/images/main-panel/search-background@2x.png b/images/main-panel/search-background@2x.png
new file mode 100644 (file)
index 0000000..ea1ad42
Binary files /dev/null and b/images/main-panel/search-background@2x.png differ
diff --git a/images/main-panel/sync.png b/images/main-panel/sync.png
new file mode 100644 (file)
index 0000000..1ea9377
Binary files /dev/null and b/images/main-panel/sync.png differ
diff --git a/images/main-panel/sync@2x.png b/images/main-panel/sync@2x.png
new file mode 100644 (file)
index 0000000..612b070
Binary files /dev/null and b/images/main-panel/sync@2x.png differ
diff --git a/images/main-panel/upload.png b/images/main-panel/upload.png
new file mode 100644 (file)
index 0000000..b6247a4
Binary files /dev/null and b/images/main-panel/upload.png differ
diff --git a/images/main-panel/upload@2x.png b/images/main-panel/upload@2x.png
new file mode 100644 (file)
index 0000000..91184e8
Binary files /dev/null and b/images/main-panel/upload@2x.png differ
diff --git a/images/minus-gray.png b/images/minus-gray.png
new file mode 100644 (file)
index 0000000..8186aa4
Binary files /dev/null and b/images/minus-gray.png differ
diff --git a/images/minus-gray@2x.png b/images/minus-gray@2x.png
new file mode 100644 (file)
index 0000000..52c7fd3
Binary files /dev/null and b/images/minus-gray@2x.png differ
diff --git a/images/notification.png b/images/notification.png
new file mode 100644 (file)
index 0000000..9c9aa1f
Binary files /dev/null and b/images/notification.png differ
diff --git a/images/pause-gray.png b/images/pause-gray.png
new file mode 100644 (file)
index 0000000..52034a6
Binary files /dev/null and b/images/pause-gray.png differ
diff --git a/images/pause-gray@2x.png b/images/pause-gray@2x.png
new file mode 100644 (file)
index 0000000..9a0c409
Binary files /dev/null and b/images/pause-gray@2x.png differ
diff --git a/images/play-gray.png b/images/play-gray.png
new file mode 100644 (file)
index 0000000..8cc1609
Binary files /dev/null and b/images/play-gray.png differ
diff --git a/images/play-gray@2x.png b/images/play-gray@2x.png
new file mode 100644 (file)
index 0000000..c2e9cb9
Binary files /dev/null and b/images/play-gray@2x.png differ
diff --git a/images/remove-gray.png b/images/remove-gray.png
new file mode 100644 (file)
index 0000000..4383533
Binary files /dev/null and b/images/remove-gray.png differ
diff --git a/images/remove-gray@2x.png b/images/remove-gray@2x.png
new file mode 100644 (file)
index 0000000..32d5431
Binary files /dev/null and b/images/remove-gray@2x.png differ
diff --git a/images/remove-red.png b/images/remove-red.png
new file mode 100644 (file)
index 0000000..bebb69c
Binary files /dev/null and b/images/remove-red.png differ
diff --git a/images/resync.png b/images/resync.png
new file mode 100644 (file)
index 0000000..9e5a846
Binary files /dev/null and b/images/resync.png differ
diff --git a/images/resync@2x.png b/images/resync@2x.png
new file mode 100644 (file)
index 0000000..7f27c85
Binary files /dev/null and b/images/resync@2x.png differ
diff --git a/images/seafile-24.png b/images/seafile-24.png
new file mode 100644 (file)
index 0000000..691aab0
Binary files /dev/null and b/images/seafile-24.png differ
diff --git a/images/seafile-32.png b/images/seafile-32.png
new file mode 100644 (file)
index 0000000..ce3fe4c
Binary files /dev/null and b/images/seafile-32.png differ
diff --git a/images/seafile.png b/images/seafile.png
new file mode 100644 (file)
index 0000000..ce3fe4c
Binary files /dev/null and b/images/seafile.png differ
diff --git a/images/seafile_auto_sync_disabled.png b/images/seafile_auto_sync_disabled.png
new file mode 100644 (file)
index 0000000..cd5c69a
Binary files /dev/null and b/images/seafile_auto_sync_disabled.png differ
diff --git a/images/seafile_transfer_1.png b/images/seafile_transfer_1.png
new file mode 100644 (file)
index 0000000..e3a7b76
Binary files /dev/null and b/images/seafile_transfer_1.png differ
diff --git a/images/seafile_transfer_2.png b/images/seafile_transfer_2.png
new file mode 100644 (file)
index 0000000..4ea5248
Binary files /dev/null and b/images/seafile_transfer_2.png differ
diff --git a/images/seafile_warning.png b/images/seafile_warning.png
new file mode 100644 (file)
index 0000000..e2fc73a
Binary files /dev/null and b/images/seafile_warning.png differ
diff --git a/images/share.png b/images/share.png
new file mode 100644 (file)
index 0000000..39de0f2
Binary files /dev/null and b/images/share.png differ
diff --git a/images/share@2x.png b/images/share@2x.png
new file mode 100644 (file)
index 0000000..4492c09
Binary files /dev/null and b/images/share@2x.png differ
diff --git a/images/svg/account.svg b/images/svg/account.svg
new file mode 100644 (file)
index 0000000..13b945a
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="448"
+   height="448"
+   viewBox="0 0 448 448"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="user.svg"
+   style="fill:#666666"
+   inkscape:export-filename="/data/seafile/seafile-dev/icons/android/user.png"
+   inkscape:export-xdpi="14.464286"
+   inkscape:export-ydpi="14.464286">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="640"
+     inkscape:window-height="480"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="0.52678571"
+     inkscape:cx="142.77966"
+     inkscape:cy="224"
+     inkscape:window-x="364"
+     inkscape:window-y="133"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2" />
+  <path
+     d="m 400,351.25 q 0,30 -18.25,47.375 Q 363.5,416 333.25,416 l -218.5,0 Q 84.5,416 66.25,398.625 48,381.25 48,351.25 48,338 48.875,325.375 49.75,312.75 52.375,298.125 55,283.5 59,271 63,258.5 69.75,246.625 76.5,234.75 85.25,226.375 94,218 106.625,213 q 12.625,-5 27.875,-5 2.25,0 10.5,5.375 8.25,5.375 18.625,12 10.375,6.625 27,12 16.625,5.375 33.375,5.375 16.75,0 33.375,-5.375 16.625,-5.375 27,-12 10.375,-6.625 18.625,-12 8.25,-5.375 10.5,-5.375 15.25,0 27.875,5 12.625,5 21.375,13.375 8.75,8.375 15.5,20.25 Q 385,258.5 389,271 q 4,12.5 6.625,27.125 2.625,14.625 3.5,27.25 Q 400,338 400,351.25 z M 320,128 q 0,39.75 -28.125,67.875 Q 263.75,224 224,224 184.25,224 156.125,195.875 128,167.75 128,128 128,88.25 156.125,60.125 184.25,32 224,32 263.75,32 291.875,60.125 320,88.25 320,128 z"
+     id="path4"
+     inkscape:connector-curvature="0" />
+</svg>
diff --git a/images/svg/arrow.svg b/images/svg/arrow.svg
new file mode 100644 (file)
index 0000000..2118c4f
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="30"
+   height="42"
+   viewBox="0 0 30 42.000001"
+   id="svg3009"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="long-arrow-up.svg"
+   inkscape:export-filename="/tmp/arrow-down.png"
+   inkscape:export-xdpi="33"
+   inkscape:export-ydpi="33">
+  <metadata
+     id="metadata3017">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs3015" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview3013"
+     showgrid="false"
+     inkscape:zoom="10.216667"
+     inkscape:cx="5.2687853"
+     inkscape:cy="13.548125"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg3009"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
+  <path
+     d="m 29.885105,27.255666 c -0.234761,-0.307603 -0.61242,-0.461404 -1.132978,-0.461404 l -7.657433,0 0,-26.01573 c 0,-0.226843 -0.117381,-0.41331 -0.352143,-0.5594 C 20.50779,0.073045 20.208142,0 19.843605,0 L 10.16077,0 C 9.7962333,0 9.4965846,0.07306 9.2618234,0.219132 9.0270617,0.365222 8.9096808,0.551689 8.9096808,0.778532 l 0,26.01573 -7.6574329,0 c -0.54680408,0 -0.92446325,0.153801 -1.13297746,0.461404 -0.20851508,0.307603 -0.14362808,0.591158 0.19466102,0.85067 L 13.984038,41.756369 c 0.261008,0.162421 0.560657,0.243632 0.898948,0.243632 0.364535,0 0.677306,-0.08122 0.938315,-0.243632 L 29.686068,28.106336 c 0.338289,-0.259512 0.403177,-0.543067 0.194662,-0.85067 z"
+     id="path3011"
+     inkscape:connector-curvature="0"
+     style="fill:#b1b1b2;fill-opacity:1"
+     sodipodi:nodetypes="cscsssscscssccscccc" />
+</svg>
diff --git a/images/svg/caret-down.svg b/images/svg/caret-down.svg
new file mode 100644 (file)
index 0000000..e0a7746
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generated by IcoMoon.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9" height="16" viewBox="0 0 9 16">
+<g>
+       <line stroke-width="1" x1="" y1="" x2="" y2="" stroke="#449FDB" opacity=""></line>
+</g>
+       <path d="M0 6.286q0-0.232 0.17-0.402t0.402-0.17h8q0.232 0 0.402 0.17t0.17 0.402-0.17 0.402l-4 4q-0.17 0.17-0.402 0.17t-0.402-0.17l-4-4q-0.17-0.17-0.17-0.402z" fill="#000000"></path>
+</svg>
diff --git a/images/svg/caret-right.svg b/images/svg/caret-right.svg
new file mode 100644 (file)
index 0000000..e5df76a
--- /dev/null
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="16"
+   height="16"
+   viewBox="0 0 16 16"
+   id="svg4083"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="caret-right.svg"
+   inkscape:export-filename="/data/github/seafile-client/images/caret-down@2x.png"
+   inkscape:export-xdpi="180"
+   inkscape:export-ydpi="180">
+  <metadata
+     id="metadata4095">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs4093" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1295"
+     inkscape:window-height="744"
+     id="namedview4091"
+     showgrid="false"
+     inkscape:zoom="14.75"
+     inkscape:cx="-9"
+     inkscape:cy="8"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4083" />
+  <g
+     id="g4085">
+    <line
+       x1="0"
+       y1="0"
+       x2="0"
+       y2="0"
+       opacity=""
+       id="line4087"
+       style="stroke:#449fdb;stroke-width:1" />
+  </g>
+  <path
+     d="m 3.6144551,4.7033531 8.7710889,0 q 0.254362,0 0.440748,0.2178967 0.186386,0.2178965 0.186386,0.5152612 0,0.2973647 -0.186386,0.5152613 L 8.440747,11.078751 q -0.1863858,0.217896 -0.4407474,0.217896 -0.2543617,0 -0.4407473,-0.217896 L 3.1737081,5.9517724 q -0.186386,-0.2178968 -0.186386,-0.5152613 0,-0.2973648 0.186386,-0.5152613 0.186386,-0.2178965 0.440747,-0.2178965 z"
+     id="path4089"
+     inkscape:connector-curvature="0"
+     style="fill:#3f3f3f;fill-opacity:1" />
+</svg>
diff --git a/images/svg/caret-up.svg b/images/svg/caret-up.svg
new file mode 100644 (file)
index 0000000..f77863f
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generated by IcoMoon.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9" height="16" viewBox="0 0 9 16">
+<g>
+       <line stroke-width="1" x1="" y1="" x2="" y2="" stroke="#449FDB" opacity=""></line>
+</g>
+       <path d="M0 10.857q0-0.232 0.17-0.402l4-4q0.17-0.17 0.402-0.17t0.402 0.17l4 4q0.17 0.17 0.17 0.402t-0.17 0.402-0.402 0.17h-8q-0.232 0-0.402-0.17t-0.17-0.402z" fill="#000000"></path>
+</svg>
diff --git a/images/svg/clock.svg b/images/svg/clock.svg
new file mode 100644 (file)
index 0000000..8f9197f
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="16"
+   height="16"
+   viewBox="0 0 16 16"
+   id="svg3060"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="clock.svg"
+   inkscape:export-filename="/home/lin/Downloads/clock@2x.png"
+   inkscape:export-xdpi="194.52686"
+   inkscape:export-ydpi="194.52686">
+  <metadata
+     id="metadata3068">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs3066" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1855"
+     inkscape:window-height="1056"
+     id="namedview3064"
+     showgrid="false"
+     inkscape:zoom="40.172504"
+     inkscape:cx="9.4836957"
+     inkscape:cy="6.5090134"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg3060" />
+  <path
+     d="M 10.121764,11.430169 7.0746779,8.3830833 V 4.2987118 H 8.9253221 V 7.6169167 L 11.430169,10.121764 z M 8,0.59742355 C 3.9119271,0.59742355 0.59742355,3.9119271 0.59742355,8 c 0,4.088073 3.31450355,7.402577 7.40257645,7.402577 4.088073,0 7.402577,-3.314504 7.402577,-7.402577 C 15.402577,3.9119271 12.088073,0.59742355 8,0.59742355 z M 8,13.551933 C 4.9334827,13.551933 2.4480676,11.066517 2.4480676,8 2.4480676,4.9334827 4.9334827,2.4480676 8,2.4480676 c 3.066517,0 5.551933,2.4854151 5.551933,5.5519324 0,3.066517 -2.485416,5.551933 -5.551933,5.551933 z"
+     id="path3062"
+     style="fill:#999999;fill-opacity:1"
+     inkscape:connector-curvature="0" />
+</svg>
diff --git a/images/svg/close.svg b/images/svg/close.svg
new file mode 100644 (file)
index 0000000..ad32182
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="16"
+   height="16"
+   viewBox="0 0 16 16"
+   id="svg4767"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="close.svg"
+   inkscape:export-filename="/data/github/seafile-client/images/close.png"
+   inkscape:export-xdpi="180"
+   inkscape:export-ydpi="180">
+  <metadata
+     id="metadata4779">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs4777" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1295"
+     inkscape:window-height="744"
+     id="namedview4775"
+     showgrid="false"
+     inkscape:zoom="14.75"
+     inkscape:cx="8"
+     inkscape:cy="8"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4767" />
+  <g
+     id="g4769">
+    <line
+       stroke-width="1"
+       x1=""
+       y1=""
+       x2=""
+       y2=""
+       stroke="#449FDB"
+       opacity=""
+       id="line4771" />
+  </g>
+  <path
+     d="m 13.389468,11.292004 c 0,0 0,0 0,0 L 9.9957702,7.898305 13.389468,4.5046068 c 0,0 0,0 0,0 0.03636,-0.036356 0.06292,-0.079004 0.0797,-0.1244495 0.04614,-0.1244496 0.01958,-0.2698739 -0.0797,-0.369853 L 11.786305,2.407142 c -0.09998,-0.099979 -0.245403,-0.126547 -0.369852,-0.079703 -0.04544,0.01678 -0.08809,0.043347 -0.12445,0.079703 0,0 0,0 0,0 L 7.8983051,5.8008402 4.5046069,2.407142 c 0,0 0,0 0,0 C 4.468251,2.370786 4.4256026,2.3442182 4.3801574,2.3274385 4.2557078,2.2812944 4.1102835,2.3071631 4.0103044,2.407142 L 2.4071421,4.0103043 c -0.099979,0.099979 -0.126547,0.2454034 -0.079704,0.369853 0.01678,0.045445 0.043348,0.088093 0.079704,0.1244495 0,0 0,0 0,0 L 5.8008403,7.898305 2.4071421,11.292004 c 0,0 0,0 0,0 -0.036356,0.03636 -0.062924,0.079 -0.079704,0.124449 -0.046144,0.124449 -0.020275,0.269874 0.079704,0.369853 l 1.6031623,1.603163 c 0.099979,0.09998 0.2454034,0.126546 0.369853,0.0797 0.045445,-0.01678 0.088093,-0.04335 0.1244495,-0.0797 0,0 0,0 0,0 L 7.8983051,9.9957703 11.292003,13.389469 c 0,0 0,0 0,0 0.03636,0.03636 0.079,0.06292 0.12445,0.0797 0.124449,0.04614 0.269873,0.02027 0.369852,-0.0797 l 1.603163,-1.603163 c 0.09998,-0.09998 0.126546,-0.245404 0.0797,-0.369853 -0.01678,-0.04545 -0.04335,-0.08809 -0.0797,-0.124449 z"
+     id="path4773"
+     inkscape:connector-curvature="0"
+     style="fill:#585859" />
+</svg>
diff --git a/images/svg/cloud.svg b/images/svg/cloud.svg
new file mode 100644 (file)
index 0000000..c0e5a73
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg3024"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="cloud.svg"
+   inkscape:export-filename="/tmp/cloud.png"
+   inkscape:export-xdpi="36"
+   inkscape:export-ydpi="36">
+  <metadata
+     id="metadata3032">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs3030" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview3028"
+     showgrid="false"
+     inkscape:zoom="9.95"
+     inkscape:cx="-3.3768842"
+     inkscape:cy="25.448101"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg3024" />
+  <path
+     d="m 57.999999,37.133483 q 0,4.637775 -3.281461,7.918364 -3.281462,3.28059 -7.918364,3.281461 H 15.066608 q -5.395637,0 -9.231123,-3.835485 Q 2,40.662337 2,35.2667 2,31.416406 4.0706219,28.222927 6.1412437,25.029448 9.524625,23.454486 q -0.05836,-0.817099 -0.05836,-1.254395 0,-6.183119 4.374699,-10.55869 4.374701,-4.3755723 10.558691,-4.374701 4.608157,0 8.356532,2.5662817 3.748374,2.5662813 5.46881,6.7083963 2.041877,-1.808418 4.841615,-1.808418 3.09156,0 5.278909,2.187351 2.187352,2.18735 2.187352,5.27891 0,2.18735 -1.196031,4.025386 3.762312,0.874591 6.212737,3.922597 Q 58,33.195207 58,37.132612 z"
+     id="path3026"
+     inkscape:connector-curvature="0"
+     style="fill:#f17f49;fill-opacity:1" />
+</svg>
diff --git a/images/svg/disk.svg b/images/svg/disk.svg
new file mode 100644 (file)
index 0000000..5db151b
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="28"
+   height="28"
+   viewBox="0 0 28 27.999999"
+   id="svg3033"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="hdd-o.svg"
+   inkscape:export-filename="/home/lin/Downloads/disk@2x.png"
+   inkscape:export-xdpi="102.85714"
+   inkscape:export-ydpi="102.85714">
+  <metadata
+     id="metadata3041">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs3039" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1855"
+     inkscape:window-height="1056"
+     id="namedview3037"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:zoom="16.232143"
+     inkscape:cx="3.3413679"
+     inkscape:cy="11.153118"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg3033" />
+  <path
+     d="m 18.863893,19.113731 q 0,0.579047 -0.411841,0.99089 -0.411841,0.411841 -0.990889,0.411841 -0.579047,0 -0.990889,-0.411841 -0.411842,-0.411843 -0.411842,-0.99089 0,-0.579046 0.411842,-0.990888 0.411842,-0.411842 0.990889,-0.411842 0.579048,0 0.990889,0.411842 0.411841,0.411842 0.411841,0.990888 z m 4.488737,0 q 0,0.579047 -0.411841,0.99089 -0.411842,0.411841 -0.990888,0.411841 -0.579048,0 -0.99089,-0.411841 -0.411841,-0.411843 -0.411841,-0.99089 0,-0.579046 0.411841,-0.990888 0.411842,-0.411842 0.99089,-0.411842 0.579046,0 0.990888,0.411842 0.411841,0.411842 0.411841,0.990888 z m 1.963823,2.805462 V 16.30827 q 0,-0.227803 -0.166083,-0.395008 -0.166084,-0.167206 -0.395009,-0.166083 H 3.43386 q -0.2278033,0 -0.3950089,0.166083 -0.1672054,0.166084 -0.1660832,0.395008 v 5.610923 q 0,0.227803 0.1660832,0.395008 0.1660833,0.167206 0.3950089,0.166083 h 21.321501 q 0.227804,0 0.395009,-0.166083 0.167205,-0.166083 0.166083,-0.395008 z M 3.7491938,13.50281 H 24.440028 L 21.68731,5.0516402 Q 21.616611,4.8238368 21.406763,4.6745864 21.196914,4.5253354 20.951156,4.5253354 H 7.2391871 q -0.2457584,0 -0.4556069,0.149251 -0.2098484,0.1492504 -0.2805461,0.3770538 z m 23.8116282,2.80546 v 5.610923 q 0,1.156972 -0.823684,1.981777 -0.823683,0.824805 -1.981777,0.823684 H 3.43386 q -1.156972,0 -1.9817776,-0.823684 Q 0.62727696,23.077286 0.62839914,21.919193 V 16.30827 q 0,-0.438773 0.28054604,-1.315199 L 4.3630287,4.3671073 Q 4.6615297,3.4379388 5.4672581,2.8588916 6.2729864,2.2798446 7.2380649,2.2798446 H 20.950034 q 0.963956,0 1.770807,0.579047 0.80685,0.5790472 1.104229,1.5082157 L 27.279154,14.993071 Q 27.5597,15.869497 27.5597,16.30827 z"
+     id="path3035"
+     style="fill:#999999;fill-opacity:1"
+     inkscape:connector-curvature="0" />
+</svg>
diff --git a/images/svg/download-alt.svg b/images/svg/download-alt.svg
new file mode 100644 (file)
index 0000000..76ea052
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg3930"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="download-alt.svg"
+   inkscape:export-filename="/tmp/download.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <metadata
+     id="metadata3938">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs3936" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview3934"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="-9"
+     inkscape:cy="26.847458"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg3930" />
+  <path
+     d="m 43.651813,48.750912 q 0,-0.845851 -0.578568,-1.465655 -0.578568,-0.619805 -1.372178,-0.617982 -0.793611,0.0018 -1.372179,0.617982 -0.578568,0.616158 -0.578568,1.465655 0,0.849497 0.578568,1.465656 0.578568,0.616158 1.372179,0.617981 0.79361,0.0018 1.372178,-0.617981 0.578568,-0.619805 0.578568,-1.465656 z m 7.802987,0 q 0,-0.845851 -0.578568,-1.465655 -0.578568,-0.619805 -1.372179,-0.617982 -0.793611,0.0018 -1.372178,0.617982 -0.578568,0.616158 -0.578568,1.465655 0,0.849497 0.578568,1.465656 0.578567,0.616158 1.372178,0.617981 0.793611,0.0018 1.372179,-0.617981 0.578568,-0.619805 0.578568,-1.465656 z m 3.899787,-7.291818 v 10.416362 q 0,1.30159 -0.853345,2.213067 Q 53.647897,55 52.42932,55 H 7.5672672 q -1.218577,0 -2.071922,-0.911477 -0.853345,-0.911477 -0.853345,-2.213067 V 41.459094 q 0,-1.301589 0.853345,-2.213066 0.853345,-0.911478 2.071922,-0.911478 H 21.73962 l 4.11483,4.427957 q 1.768131,1.822954 4.14555,1.822954 2.377419,0 4.14555,-1.822954 L 38.2911,38.33455 h 14.141633 q 1.218577,0 2.071922,0.911478 0.853345,0.911477 0.853345,2.213066 z m -9.903922,-18.52304 q 0.518833,1.334403 -0.426673,2.278693 l -13.65352,14.583636 q -0.547847,0.617981 -1.372179,0.617981 -0.824331,0 -1.372178,-0.617981 L 14.972595,25.214747 q -0.945507,-0.94429 -0.426673,-2.278693 0.518834,-1.268776 1.798851,-1.268776 h 7.80128 V 7.0836422 q 0,-0.8458509 0.578568,-1.4656554 0.578568,-0.6198045 1.372179,-0.6179816 h 7.80128 q 0.791904,0 1.372179,0.6179816 0.580274,0.6179816 0.578568,1.4656554 V 21.667278 h 7.80128 q 1.280017,0 1.798851,1.268776 z"
+     id="path3932"
+     inkscape:connector-curvature="0"
+     style="fill:#585859;fill-opacity:1" />
+</svg>
diff --git a/images/svg/exclamation.svg b/images/svg/exclamation.svg
new file mode 100644 (file)
index 0000000..4438cce
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg4411"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="exclamation.svg"
+   inkscape:export-filename="/tmp/exclamation.png"
+   inkscape:export-xdpi="36"
+   inkscape:export-ydpi="36">
+  <metadata
+     id="metadata4419">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs4417" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview4415"
+     showgrid="false"
+     inkscape:zoom="10.216667"
+     inkscape:cx="30"
+     inkscape:cy="30"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4411" />
+  <path
+     d="m 35.619886,42.17744 v 6.557117 q 0,0.7615 -0.556043,1.317543 -0.556044,0.556044 -1.317544,0.556044 h -7.493473 q -0.7615,0 -1.317544,-0.556044 Q 24.37924,49.496057 24.37924,48.734557 V 42.17744 q 0,-0.7615 0.556042,-1.317543 0.556044,-0.556044 1.317544,-0.556044 h 7.493473 q 0.7615,0 1.317544,0.556044 0.556043,0.556043 0.556043,1.317543 z m 0.87778,-30.911997 -0.820077,22.481293 q -0.02885,0.7615 -0.599758,1.317544 -0.570906,0.556043 -1.331532,0.556043 h -7.493473 q -0.7615,0 -1.331532,-0.556043 -0.570031,-0.556044 -0.599757,-1.317544 L 23.50146,11.265443 Q 23.47261,10.503944 24.013789,9.9479 24.554971,9.391856 25.316469,9.391856 h 9.367061 q 0.7615,0 1.30268,0.556044 0.541181,0.556044 0.51233,1.317543 z"
+     id="path4413"
+     style="fill:#f17f49;fill-opacity:1"
+     inkscape:connector-curvature="0" />
+</svg>
diff --git a/images/svg/folder-open.svg b/images/svg/folder-open.svg
new file mode 100644 (file)
index 0000000..4064496
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg5116"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="folder-open.svg"
+   inkscape:export-filename="/tmp/folder-open.png"
+   inkscape:export-xdpi="36"
+   inkscape:export-ydpi="36">
+  <metadata
+     id="metadata5124">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs5122" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview5120"
+     showgrid="false"
+     inkscape:zoom="10.216667"
+     inkscape:cx="30"
+     inkscape:cy="30"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg5116" />
+  <path
+     d="M 46.370312,51.281406 56.1925,25.088906 H 13.629688 L 3.8075,51.281406 z M 10.355625,21.814843 3.8075,51.281406 V 8.718594 h 14.733281 l 6.548125,6.548125 h 21.281406 v 6.548124 z"
+     id="path5118"
+     inkscape:connector-curvature="0"
+     style="fill:#585859;fill-opacity:1" />
+</svg>
diff --git a/images/svg/info-sign.svg b/images/svg/info-sign.svg
new file mode 100644 (file)
index 0000000..7535759
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg7784"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="info-sign.svg"
+   inkscape:export-filename="/tmp/info.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <metadata
+     id="metadata7792">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs7790" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview7788"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="-2.6355932"
+     inkscape:cy="26.847458"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg7784" />
+  <path
+     d="M 39.165998,47.186998 V 41.458 q 0,-0.501314 -0.322846,-0.824159 -0.322845,-0.322845 -0.824156,-0.322845 h -3.437 V 21.976994 q 0,-0.501312 -0.322844,-0.824158 -0.322846,-0.322845 -0.824159,-0.322845 H 21.976994 q -0.501312,0 -0.824158,0.322845 -0.322845,0.322846 -0.322845,0.824158 v 5.729 q 0,0.501313 0.322845,0.824158 0.322846,0.322846 0.824158,0.322846 h 3.437 v 11.457998 h -3.437 q -0.501312,0 -0.824158,0.322845 -0.322845,0.322845 -0.322845,0.824159 v 5.728998 q 0,0.501314 0.322845,0.824159 0.322846,0.322845 0.824158,0.322845 h 16.042002 q 0.501311,0 0.824156,-0.322845 0.322846,-0.322845 0.322846,-0.824159 z m -4.584002,-32.084 V 9.3739977 q 0,-0.5013124 -0.322844,-0.824158 -0.322846,-0.3228456 -0.824159,-0.3228456 h -6.876002 q -0.501313,0 -0.824159,0.3228456 -0.322844,0.3228456 -0.322844,0.824158 v 5.7290003 q 0,0.501312 0.322844,0.824156 Q 26.057678,16.25 26.558991,16.25 h 6.876002 q 0.501313,0 0.824159,-0.322846 0.322844,-0.322844 0.322844,-0.824156 z M 57.5,30 q 0,7.483594 -3.687656,13.804142 Q 50.12469,50.12469 43.804142,53.812344 37.483594,57.5 30,57.5 22.516406,57.5 16.195858,53.812344 9.87531,50.12469 6.1876549,43.804142 2.5,37.483594 2.5,30 2.5,22.516406 6.1876549,16.195858 9.87531,9.8753101 16.195858,6.1876554 22.516406,2.5 30,2.5 37.483594,2.5 43.804142,6.1876554 50.12469,9.8753101 53.812344,16.195858 57.5,22.516406 57.5,30 z"
+     id="path7786"
+     inkscape:connector-curvature="0"
+     style="fill:#585859;fill-opacity:1" />
+</svg>
diff --git a/images/svg/link.svg b/images/svg/link.svg
new file mode 100644 (file)
index 0000000..7265876
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="32"
+   height="32"
+   viewBox="0 0 32 32"
+   id="svg9579"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="link.svg"
+   inkscape:export-filename="/tmp/link-red.png"
+   inkscape:export-xdpi="168.75"
+   inkscape:export-ydpi="168.75">
+  <metadata
+     id="metadata9587">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs9585" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview9583"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="-8"
+     inkscape:cy="16"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg9579" />
+  <path
+     d="M 27.208113,4.8946702 27.105734,4.7922939 c -2.390392,-2.390392 -6.301795,-2.390392 -8.692187,0 l -5.53804,5.5388521 c -2.390392,2.390392 -2.390392,6.301794 0,8.691373 l 0.102379,0.102378 c 0.199062,0.199065 0.410314,0.378627 0.628065,0.545193 l 2.027204,-2.027204 c -0.236441,-0.139751 -0.459879,-0.306313 -0.663005,-0.50944 l -0.102378,-0.102378 c -1.297573,-1.297574 -1.297573,-3.409275 0,-4.706848 l 5.538039,-5.5380376 c 1.297571,-1.297572 3.409274,-1.297572 4.706845,0 l 0.102378,0.1023752 c 1.297573,1.2975718 1.297573,3.4100864 0,4.7068454 l -2.505768,2.505768 c 0.434692,1.074133 0.641068,2.218952 0.623194,3.361335 l 3.874838,-3.874839 c 2.390392,-2.390391 2.390392,-6.301794 0,-8.6913739 z M 19.02293,12.87429 c -0.199066,-0.199066 -0.410317,-0.378629 -0.628069,-0.54438 l -2.0272,2.027201 c 0.236437,0.139751 0.459878,0.306316 0.663005,0.509443 l 0.102378,0.102378 c 1.29757,1.297571 1.29757,3.409274 0,4.706845 l -5.538853,5.538854 c -1.297571,1.29757 -3.409274,1.29757 -4.7068458,0 L 6.7849689,25.112252 c -1.2975718,-1.298383 -1.2975718,-3.409274 0,-4.706846 L 9.290734,17.899637 C 8.8560436,16.825503 8.6496672,15.680684 8.6675423,14.538301 L 4.792702,18.41314 c -2.3903919,2.390392 -2.3903919,6.301795 0,8.692187 l 0.1023752,0.102378 c 2.3903922,2.390393 6.3017958,2.390393 8.6921878,0 l 5.53804,-5.538039 c 2.390392,-2.390393 2.390392,-6.301795 0,-8.692188 L 19.022926,12.8751 z"
+     id="path9581"
+     style="fill:#ff2a2a;fill-opacity:1"
+     inkscape:connector-curvature="0" />
+</svg>
diff --git a/images/svg/ok.svg b/images/svg/ok.svg
new file mode 100644 (file)
index 0000000..61bde3b
--- /dev/null
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg3065"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="ok.svg"
+   inkscape:export-filename="/tmp/ok.png"
+   inkscape:export-xdpi="36"
+   inkscape:export-ydpi="36">
+  <metadata
+     id="metadata3073">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs3071" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview3069"
+     showgrid="false"
+     inkscape:zoom="9.95"
+     inkscape:cx="30"
+     inkscape:cy="30"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="layer1" />
+  <path
+     sodipodi:type="arc"
+     style="fill:#54c73f;fill-opacity:1"
+     id="path3845"
+     sodipodi:cx="15.979899"
+     sodipodi:cy="4.924623"
+     sodipodi:rx="7.3366833"
+     sodipodi:ry="6.3316584"
+     d="m 23.316583,4.924623 a 7.3366833,6.3316584 0 1 1 -14.6733669,0 7.3366833,6.3316584 0 1 1 14.6733669,0 z"
+     transform="matrix(4.0890412,0,0,4.7380953,-35.342467,6.6666668)" />
+  <g
+     inkscape:groupmode="layer"
+     id="layer1"
+     inkscape:label="ok">
+    <path
+       d="m 47.949308,21.616068 q 0,0.926208 -0.648828,1.575037 L 27.382549,43.109034 q -0.648828,0.648829 -1.575034,0.648829 -0.926206,0 -1.575034,-0.648829 L 12.698828,31.575379 Q 12.05,30.926551 12.05,30.000344 q 0,-0.926206 0.648828,-1.575033 l 3.150068,-3.15007 q 0.648828,-0.648829 1.575035,-0.648829 0.926206,0 1.575035,0.648829 l 6.80924,6.832067 15.192825,-15.216342 q 0.648828,-0.648828 1.575034,-0.648828 0.926209,0 1.575037,0.648828 l 3.15007,3.150069 Q 47.95,20.689862 47.95,21.616068 z"
+       id="path3067"
+       style="fill:#ffffff;fill-opacity:1"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/images/svg/pause.svg b/images/svg/pause.svg
new file mode 100644 (file)
index 0000000..76aeca2
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg6322"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="pause.svg"
+   inkscape:export-filename="/tmp/pause.png"
+   inkscape:export-xdpi="36"
+   inkscape:export-ydpi="36">
+  <metadata
+     id="metadata6330">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs6328" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview6326"
+     showgrid="false"
+     inkscape:zoom="3.9333333"
+     inkscape:cx="-64.245763"
+     inkscape:cy="30"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg6322" />
+  <path
+     d="M 55,7.0834549 V 52.916545 q 0,0.846799 -0.618328,1.465127 Q 53.763344,55 52.916545,55 H 36.249878 Q 35.40308,55 34.784752,54.381672 34.166424,53.763344 34.166424,52.916545 V 7.0834549 q 0,-0.8467985 0.618328,-1.4651267 Q 35.40308,5 36.249878,5 H 52.916545 Q 53.763344,5 54.381672,5.6183282 55,6.2366564 55,7.0834549 z m -29.166424,0 V 52.916545 q 0,0.846799 -0.618328,1.465127 Q 24.59692,55 23.750122,55 H 7.083455 Q 6.2366565,55 5.6183282,54.381672 5.0000001,53.763344 5.0000001,52.916545 V 7.0834549 q 0,-0.8467985 0.6183281,-1.4651267 Q 6.2366565,5 7.083455,5 h 16.666667 q 0.846798,0 1.465126,0.6183282 0.618328,0.6183282 0.618328,1.4651267 z"
+     id="path6324"
+     inkscape:connector-curvature="0"
+     style="fill:#f17f49;fill-opacity:1" />
+</svg>
diff --git a/images/svg/play.svg b/images/svg/play.svg
new file mode 100644 (file)
index 0000000..2fe7524
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg8926"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="play.svg"
+   inkscape:export-filename="/tmp/play.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <metadata
+     id="metadata8934">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8932" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview8930"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="-3.6355932"
+     inkscape:cy="32.271186"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg8926" />
+  <path
+     d="m 47.530175,30.798134 -34.210638,19.01248 q -0.592923,0.334693 -1.017058,0.0779 -0.424134,-0.256786 -0.425577,-0.927611 V 11.039808 q 0,-0.669382 0.425577,-0.927614 0.425578,-0.2582325 1.017058,0.0779 l 34.210638,19.012484 q 0.592922,0.33469 0.592922,0.799218 0,0.464529 -0.592922,0.799221 z"
+     id="path8928"
+     inkscape:connector-curvature="0"
+     style="fill:#585859;fill-opacity:1" />
+</svg>
diff --git a/images/svg/plus.svg b/images/svg/plus.svg
new file mode 100644 (file)
index 0000000..818b02c
--- /dev/null
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="16"
+   height="16"
+   viewBox="0 0 16 16"
+   id="svg4680"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="plus.svg"
+   inkscape:export-filename="/data/github/seafile-client/images/plus.png"
+   inkscape:export-xdpi="180"
+   inkscape:export-ydpi="180">
+  <metadata
+     id="metadata4692">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs4690" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1295"
+     inkscape:window-height="744"
+     id="namedview4688"
+     showgrid="false"
+     inkscape:zoom="14.75"
+     inkscape:cx="-1.5677966"
+     inkscape:cy="8"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4680" />
+  <g
+     id="g4682">
+    <line
+       x1="0"
+       y1="0"
+       x2="0"
+       y2="0"
+       opacity=""
+       id="line4684"
+       style="stroke:#449fdb;stroke-width:1" />
+  </g>
+  <path
+     d="M 1.715,8.857 V 7.143 q 0,-0.357 0.25,-0.607 0.25,-0.25 0.607,-0.25 H 6.286 V 2.572 q 0,-0.357 0.25,-0.607 0.25,-0.25 0.607,-0.25 h 1.714 q 0.357,0 0.607,0.25 0.25,0.25 0.25,0.607 v 3.714 h 3.714 q 0.357,0 0.607,0.25 0.25,0.25 0.25,0.607 v 1.714 q 0,0.357 -0.25,0.607 -0.25,0.25 -0.607,0.25 H 9.714 v 3.714 q 0,0.357 -0.25,0.607 -0.25,0.25 -0.607,0.25 H 7.143 q -0.357,0 -0.607,-0.25 -0.25,-0.25 -0.25,-0.607 V 9.714 H 2.572 q -0.357,0 -0.607,-0.25 -0.25,-0.25 -0.25,-0.607 z"
+     id="path4686"
+     inkscape:connector-curvature="0"
+     style="fill:#585859" />
+</svg>
diff --git a/images/svg/question.svg b/images/svg/question.svg
new file mode 100644 (file)
index 0000000..011abf8
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg5006"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="question.svg"
+   inkscape:export-filename="/tmp/question.png"
+   inkscape:export-xdpi="36"
+   inkscape:export-ydpi="36">
+  <metadata
+     id="metadata5014">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs5012" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview5010"
+     showgrid="false"
+     inkscape:zoom="3.9333333"
+     inkscape:cx="-28"
+     inkscape:cy="30"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg5006" />
+  <path
+     d="m 34.890523,42.0545 v 8.036 q 0,0.536 -0.402,0.938 -0.402,0.402 -0.938,0.402 h -8.036 q -0.536,0 -0.938,-0.402 -0.402,-0.402 -0.402,-0.938 v -8.036 q 0,-0.536 0.402,-0.938 0.402,-0.402 0.938,-0.402 h 8.036 q 0.536,0 0.938,0.402 0.402,0.402 0.402,0.938 z m 10.581,-20.09 q 0,1.808 -0.519,3.382 -0.519,1.574 -1.172,2.561 -0.653,0.987 -1.842,1.992 -1.189,1.005 -1.925,1.456 -0.736,0.451 -2.042,1.189 -1.373,0.77 -2.294,2.176 -0.921,1.406 -0.921,2.243 0,0.569 -0.402,1.088 -0.402,0.519 -0.938,0.519 h -8.036 q -0.502,0 -0.854,-0.619 -0.352,-0.619 -0.352,-1.256 v -1.507 q 0,-2.779 2.176,-5.24 2.176,-2.461 4.788,-3.633 1.975,-0.904 2.813,-1.875 0.838,-0.971 0.837,-2.545 0,-1.406 -1.557,-2.478 -1.557,-1.072 -3.599,-1.071 -2.176,0 -3.616,0.971 -1.172,0.837 -3.583,3.85 -0.435,0.536 -1.038,0.536 -0.402,0 -0.837,-0.268 l -5.491,-4.185 q -0.435,-0.335 -0.519,-0.837 -0.084,-0.502 0.184,-0.938 5.357,-8.906 15.536,-8.906 2.679,0 5.391,1.038 2.712,1.038 4.888,2.779 2.176,1.741 3.549,4.269 1.373,2.528 1.373,5.307 z"
+     id="path5008"
+     inkscape:connector-curvature="0"
+     style="fill:#f17f49;fill-opacity:1" />
+</svg>
diff --git a/images/svg/refresh.svg b/images/svg/refresh.svg
new file mode 100644 (file)
index 0000000..a25e482
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg5029"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="refresh.svg"
+   inkscape:export-filename="/tmp/refresh.png"
+   inkscape:export-xdpi="36"
+   inkscape:export-ydpi="36">
+  <metadata
+     id="metadata5037">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs5035" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview5033"
+     showgrid="false"
+     inkscape:zoom="10.216667"
+     inkscape:cx="6.7047318"
+     inkscape:cy="30"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg5029" />
+  <path
+     d="m 32.426902,6.5012004 8.535401,8.5354006 q 0.495053,0.495053 0.496132,1.219482 0.0011,0.724429 -0.496088,1.219464 l -8.53509,8.535091 q -0.800165,0.800163 -1.886283,0.362712 -1.066912,-0.418246 -1.04773,-1.581172 l -9.5e-5,-5.257712 q -5.429479,0.210081 -9.258534,4.039136 -1.981208,1.981208 -3.010725,4.553499 -1.029517,2.57229 -1.029469,5.201145 4.8e-5,2.628856 1.029659,5.201184 1.029611,2.572328 3.010891,4.553609 1.98128,1.98128 4.553608,3.01089 2.572328,1.029611 5.201184,1.029659 2.628855,4.8e-5 5.201145,-1.029469 2.572291,-1.029517 4.553499,-3.010725 2.267133,-2.267132 3.295575,-5.277923 1.028444,-3.010787 0.609091,-6.210446 -0.05761,-0.32434 0.210168,-0.666811 0.266721,-0.266723 0.647605,-0.304057 l 5.238508,0.0193 q 0.324339,-0.01919 0.571865,0.209125 0.24753,0.228319 0.285941,0.571866 0.438582,4.590903 -1.132891,8.925712 -1.571473,4.334809 -4.84788,7.611217 -2.972346,2.972345 -6.838784,4.51502 -3.866437,1.542675 -7.79265,1.542603 -3.926212,-7.1e-5 -7.792707,-1.542887 Q 18.331754,50.933294 15.3593,47.96084 12.386847,44.988387 10.844031,41.121892 9.3012151,37.255398 9.301144,33.329186 q -7.2e-5,-3.926214 1.542603,-7.792651 1.542675,-3.866438 4.51502,-6.838784 2.800577,-2.800576 6.477105,-4.362459 3.676528,-1.561883 7.640081,-1.675969 l 0.01805,-4.9344375 q -0.03843,-1.1437238 1.066877,-1.6003392 1.066898,-0.4182076 1.867092,0.3819863 z"
+     id="path5031"
+     inkscape:connector-curvature="0"
+     style="fill:#585859;fill-opacity:1" />
+</svg>
diff --git a/images/svg/repo.svg b/images/svg/repo.svg
new file mode 100644 (file)
index 0000000..9c5ac0c
--- /dev/null
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="72"
+   height="72"
+   viewBox="0 0 72 72"
+   id="svg2"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="library-enc.svg"
+   inkscape:export-filename="/tmp/encrypted-repo.png"
+   inkscape:export-xdpi="45"
+   inkscape:export-ydpi="45">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="8.5138889"
+     inkscape:cx="36"
+     inkscape:cy="36"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2" />
+  <path
+     d="m 60.544243,60.545075 c 0,0 -43.636062,0 -49.090152,0 C 6,60.545075 6,55.090984 6,55.090984 V 36.000416 L 19.636477,11.454925 H 52.363523 L 66,36.000416 c 0,0 0,13.636478 0,19.090568 0,5.454091 -5.454091,5.454091 -5.454091,5.454091 z M 49.635227,16.909014 h -27.27212 l -9.545701,19.090569 h 12.272329 c 0,0 5.454091,0 5.454091,5.454091 v 2.727462 h 10.909016 v -2.727462 c 0,0 0,-5.454091 5.45409,-5.454091 h 12.272329 l -9.5457,-19.090569 z m 10.909016,24.54466 H 47.565256 c -0.379161,0.71749 -0.657491,1.576645 -0.657491,2.727462 0,5.45409 -5.454091,5.45409 -5.454091,5.45409 H 30.544659 c 0,0 -5.45409,0 -5.45409,-5.45409 0,-1.150817 -0.27833,-2.009972 -0.657492,-2.727462 H 11.454091 V 55.090151 H 60.544243 V 41.453674 z M 23.72642,27.818029 h 24.545494 l 1.363313,2.727462 h -27.27212 l 1.363313,-2.727462 z m 2.726629,-5.454924 h 19.090568 l 1.363315,2.727462 H 25.088901 l 1.363315,-2.727462 z"
+     id="path4"
+     style="fill:#999999;fill-opacity:1"
+     inkscape:connector-curvature="0" />
+  <g
+     inkscape:groupmode="layer"
+     id="layer1"
+     inkscape:label="lock"
+     style="display:none">
+    <g
+       style="fill:#ff6600"
+       id="g3008"
+       transform="matrix(0.08874904,0,0,0.08874904,42.893874,32.04591)">
+      <path
+         id="path3000"
+         d="m 176,256 q 0,-13.25 -9.375,-22.625 Q 157.25,224 144,224 130.75,224 121.375,233.375 112,242.75 112,256 q 0,9.25 4.75,16.75 4.75,7.5 12.75,11.75 l -17.25,57.25 q -1.25,3.75 1.25,7 2.5,3.25 6.5,3.25 l 48,0 q 4,0 6.5,-3.25 2.5,-3.25 1.25,-7 L 158.5,284.5 q 8,-4.25 12.75,-11.75 Q 176,265.25 176,256 z m -96,-64 128,0 0,-48 Q 208,117.5 189.25,98.75 170.5,80 144,80 117.5,80 98.75,98.75 80,117.5 80,144 l 0,48 z m 208,24 0,144 q 0,10 -7,17 -7,7 -17,7 L 24,384 Q 14,384 7,377 0,370 0,360 L 0,216 q 0,-10 7,-17 7,-7 17,-7 l 8,0 0,-48 q 0,-46 33,-79 33,-33 79,-33 46,0 79,33 33,33 33,79 l 0,48 8,0 q 10,0 17,7 7,7 7,17 z"
+         inkscape:connector-curvature="0"
+         style="fill:#ff6600" />
+    </g>
+  </g>
+  <g
+     style="fill:#ff6600"
+     id="g3008-1"
+     transform="matrix(0.08874904,0,0,0.08874904,40.440276,26.465444)">
+    <path
+       id="path3000-6"
+       d="m 176,256 q 0,-13.25 -9.375,-22.625 Q 157.25,224 144,224 130.75,224 121.375,233.375 112,242.75 112,256 q 0,9.25 4.75,16.75 4.75,7.5 12.75,11.75 l -17.25,57.25 q -1.25,3.75 1.25,7 2.5,3.25 6.5,3.25 l 48,0 q 4,0 6.5,-3.25 2.5,-3.25 1.25,-7 L 158.5,284.5 q 8,-4.25 12.75,-11.75 Q 176,265.25 176,256 z m -96,-64 128,0 0,-48 Q 208,117.5 189.25,98.75 170.5,80 144,80 117.5,80 98.75,98.75 80,117.5 80,144 l 0,48 z m 208,24 0,144 q 0,10 -7,17 -7,7 -17,7 L 24,384 Q 14,384 7,377 0,370 0,360 L 0,216 q 0,-10 7,-17 7,-7 17,-7 l 8,0 0,-48 q 0,-46 33,-79 33,-33 79,-33 46,0 79,33 33,33 33,79 l 0,48 8,0 q 10,0 17,7 7,7 7,17 z"
+       inkscape:connector-curvature="0"
+       style="fill:#ff6600" />
+  </g>
+</svg>
diff --git a/images/svg/rotate.svg b/images/svg/rotate.svg
new file mode 100644 (file)
index 0000000..aab54da
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="60"
+   height="60"
+   viewBox="0 0 60 60"
+   id="svg6957"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="rotate.svg"
+   style="fill:#000000"
+   inkscape:export-filename="/tmp/rotate.png"
+   inkscape:export-xdpi="36"
+   inkscape:export-ydpi="36">
+  <metadata
+     id="metadata6965">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs6963" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1215"
+     inkscape:window-height="776"
+     id="namedview6961"
+     showgrid="false"
+     inkscape:zoom="10.216667"
+     inkscape:cx="12.773247"
+     inkscape:cy="30"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg6957" />
+  <path
+     d="m 54.186198,35.208333 q 0,0.162761 -0.03255,0.227865 -2.083336,8.723958 -8.723961,14.14388 Q 38.789062,55 29.869792,55 25.117187,55 20.673828,53.209635 16.230469,51.419271 12.747396,48.098958 l -4.1992189,4.199219 q -0.6184896,0.61849 -1.4648438,0.61849 -0.8463541,0 -1.4648437,-0.61849 Q 5,51.679687 5,50.833333 L 5,36.25 q 0,-0.846354 0.6184896,-1.464844 0.6184896,-0.618489 1.4648437,-0.618489 l 14.5833337,0 q 0.846354,0 1.464843,0.618489 Q 23.75,35.403646 23.75,36.25 q 0,0.846354 -0.61849,1.464844 l -4.459635,4.459635 q 2.311198,2.148438 5.240885,3.320313 2.929688,1.171875 6.08724,1.171875 4.361979,0 8.138021,-2.115886 3.776041,-2.115885 6.054687,-5.826823 0.358073,-0.553385 1.725261,-3.808593 0.260416,-0.748698 0.976562,-0.748698 l 6.25,0 q 0.423177,0 0.732422,0.309244 0.309245,0.309245 0.309245,0.732422 z M 55,9.166667 55,23.75 q 0,0.846354 -0.61849,1.464844 -0.618489,0.618489 -1.464843,0.618489 l -14.583334,0 q -0.846354,0 -1.464843,-0.618489 Q 36.25,24.596354 36.25,23.75 q 0,-0.846354 0.61849,-1.464844 l 4.492187,-4.492187 Q 36.542969,13.333333 30,13.333333 q -4.361979,0 -8.138021,2.115886 -3.776041,2.115885 -6.054687,5.826823 -0.358073,0.553385 -1.725261,3.808593 -0.260416,0.748698 -0.976562,0.748698 l -6.4778648,0 q -0.4231771,0 -0.7324219,-0.309245 -0.3092448,-0.309244 -0.3092448,-0.732421 l 0,-0.227865 Q 7.7018229,15.839844 14.375,10.419922 21.048177,5 30,5 q 4.752604,0 9.244792,1.806641 4.492187,1.80664 7.97526,5.094401 l 4.231771,-4.199219 q 0.618489,-0.61849 1.464844,-0.61849 0.846354,0 1.464843,0.61849 Q 55,8.320312 55,9.166667 z"
+     id="path6959"
+     inkscape:connector-curvature="0"
+     style="fill:#f17f49;fill-opacity:1" />
+</svg>
diff --git a/images/svg/share.svg b/images/svg/share.svg
new file mode 100644 (file)
index 0000000..1984fd5
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="512"
+   height="512"
+   viewBox="0 0 512 512"
+   id="svg3034"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="share.svg"
+   inkscape:export-filename="/home/lin/Downloads/share.png"
+   inkscape:export-xdpi="2.8125"
+   inkscape:export-ydpi="2.8125">
+  <metadata
+     id="metadata3043">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs3041" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1855"
+     inkscape:window-height="1056"
+     id="namedview3039"
+     showgrid="false"
+     inkscape:zoom="0.88769531"
+     inkscape:cx="190.6632"
+     inkscape:cy="197.22969"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg3034" />
+  <g
+     id="icomoon-ignore" />
+  <path
+     d="m 378.63147,335.52475 c -17.61191,0 -33.50786,7.76112 -44.85342,20.22497 L 165.69123,266.49064 c 0.51245,-3.41791 0.78622,-6.91948 0.78622,-10.49064 0,-3.57116 -0.27377,-7.07273 -0.78622,-10.48981 l 168.08682,-89.25908 c 11.34556,12.46302 27.24151,20.22414 44.85342,20.22414 34.46177,0 62.39824,-29.67019 62.39824,-66.27063 0,-36.600439 -27.93647,-66.270627 -62.39824,-66.270627 -34.46177,0 -62.39824,29.670188 -62.39824,66.270627 0,3.57116 0.27455,7.07273 0.78622,10.48981 l -168.08682,89.25991 c -11.34556,-12.46302 -27.24151,-20.22497 -44.85342,-20.22497 -34.46177,0 -62.398241,29.67102 -62.398241,66.27063 0,36.60127 27.936471,66.27063 62.398241,66.27063 17.61191,0 33.50786,-7.76112 44.85342,-20.22414 l 168.08682,89.25908 c -0.51167,3.41708 -0.78622,6.91865 -0.78622,10.48981 0,36.60127 27.93647,66.27063 62.39824,66.27063 34.46177,0 62.39824,-29.66936 62.39824,-66.27063 0,-36.59961 -27.93647,-66.27063 -62.39824,-66.27063 z"
+     id="path3037"
+     style="fill:#999999;fill-opacity:1"
+     inkscape:connector-curvature="0" />
+</svg>
diff --git a/images/sync/cloud-sync.png b/images/sync/cloud-sync.png
new file mode 100644 (file)
index 0000000..becbf7f
Binary files /dev/null and b/images/sync/cloud-sync.png differ
diff --git a/images/sync/cloud-sync@2x.png b/images/sync/cloud-sync@2x.png
new file mode 100644 (file)
index 0000000..c558d29
Binary files /dev/null and b/images/sync/cloud-sync@2x.png differ
diff --git a/images/sync/cloud-synced.png b/images/sync/cloud-synced.png
new file mode 100644 (file)
index 0000000..768acaa
Binary files /dev/null and b/images/sync/cloud-synced.png differ
diff --git a/images/sync/cloud-synced@2x.png b/images/sync/cloud-synced@2x.png
new file mode 100644 (file)
index 0000000..c6a2f77
Binary files /dev/null and b/images/sync/cloud-synced@2x.png differ
diff --git a/images/sync/cloud-unsynced.png b/images/sync/cloud-unsynced.png
new file mode 100644 (file)
index 0000000..94e81d2
Binary files /dev/null and b/images/sync/cloud-unsynced.png differ
diff --git a/images/sync/cloud-unsynced@2x.png b/images/sync/cloud-unsynced@2x.png
new file mode 100644 (file)
index 0000000..13ffaf7
Binary files /dev/null and b/images/sync/cloud-unsynced@2x.png differ
diff --git a/images/sync/done.png b/images/sync/done.png
new file mode 100644 (file)
index 0000000..5996a25
Binary files /dev/null and b/images/sync/done.png differ
diff --git a/images/sync/done@2x.png b/images/sync/done@2x.png
new file mode 100644 (file)
index 0000000..02ed7a3
Binary files /dev/null and b/images/sync/done@2x.png differ
diff --git a/images/sync/exclamation.png b/images/sync/exclamation.png
new file mode 100755 (executable)
index 0000000..59c87f4
Binary files /dev/null and b/images/sync/exclamation.png differ
diff --git a/images/sync/minus-sign.png b/images/sync/minus-sign.png
new file mode 100755 (executable)
index 0000000..7b5138a
Binary files /dev/null and b/images/sync/minus-sign.png differ
diff --git a/images/sync/pause.png b/images/sync/pause.png
new file mode 100755 (executable)
index 0000000..3f1dfc6
Binary files /dev/null and b/images/sync/pause.png differ
diff --git a/images/sync/pause@2x.png b/images/sync/pause@2x.png
new file mode 100755 (executable)
index 0000000..03b01a6
Binary files /dev/null and b/images/sync/pause@2x.png differ
diff --git a/images/sync/question.png b/images/sync/question.png
new file mode 100755 (executable)
index 0000000..51020d7
Binary files /dev/null and b/images/sync/question.png differ
diff --git a/images/sync/status-done.png b/images/sync/status-done.png
new file mode 100644 (file)
index 0000000..0147e92
Binary files /dev/null and b/images/sync/status-done.png differ
diff --git a/images/sync/status-done@2x.png b/images/sync/status-done@2x.png
new file mode 100644 (file)
index 0000000..636ceea
Binary files /dev/null and b/images/sync/status-done@2x.png differ
diff --git a/images/sync/status-syncing.png b/images/sync/status-syncing.png
new file mode 100644 (file)
index 0000000..af8d4a5
Binary files /dev/null and b/images/sync/status-syncing.png differ
diff --git a/images/sync/status-syncing@2x.png b/images/sync/status-syncing@2x.png
new file mode 100644 (file)
index 0000000..c241cb8
Binary files /dev/null and b/images/sync/status-syncing@2x.png differ
diff --git a/images/sync/waiting.png b/images/sync/waiting.png
new file mode 100755 (executable)
index 0000000..8d8fb7f
Binary files /dev/null and b/images/sync/waiting.png differ
diff --git a/images/sync/waiting@2x.png b/images/sync/waiting@2x.png
new file mode 100755 (executable)
index 0000000..2404dec
Binary files /dev/null and b/images/sync/waiting@2x.png differ
diff --git a/images/sync_now-gray.png b/images/sync_now-gray.png
new file mode 100644 (file)
index 0000000..0d4f3b1
Binary files /dev/null and b/images/sync_now-gray.png differ
diff --git a/images/sync_now-gray@2x.png b/images/sync_now-gray@2x.png
new file mode 100644 (file)
index 0000000..547ba52
Binary files /dev/null and b/images/sync_now-gray@2x.png differ
diff --git a/images/tabs/highlighted/history-orange.png b/images/tabs/highlighted/history-orange.png
new file mode 100644 (file)
index 0000000..418ee09
Binary files /dev/null and b/images/tabs/highlighted/history-orange.png differ
diff --git a/images/tabs/highlighted/history-orange@2x.png b/images/tabs/highlighted/history-orange@2x.png
new file mode 100644 (file)
index 0000000..1320892
Binary files /dev/null and b/images/tabs/highlighted/history-orange@2x.png differ
diff --git a/images/tabs/highlighted/library-orange.png b/images/tabs/highlighted/library-orange.png
new file mode 100644 (file)
index 0000000..2dd74cc
Binary files /dev/null and b/images/tabs/highlighted/library-orange.png differ
diff --git a/images/tabs/highlighted/library-orange@2x.png b/images/tabs/highlighted/library-orange@2x.png
new file mode 100644 (file)
index 0000000..105fde1
Binary files /dev/null and b/images/tabs/highlighted/library-orange@2x.png differ
diff --git a/images/tabs/highlighted/search-orange.png b/images/tabs/highlighted/search-orange.png
new file mode 100644 (file)
index 0000000..a814a1c
Binary files /dev/null and b/images/tabs/highlighted/search-orange.png differ
diff --git a/images/tabs/highlighted/search-orange@2x.png b/images/tabs/highlighted/search-orange@2x.png
new file mode 100644 (file)
index 0000000..b7f3975
Binary files /dev/null and b/images/tabs/highlighted/search-orange@2x.png differ
diff --git a/images/tabs/highlighted/star-orange.png b/images/tabs/highlighted/star-orange.png
new file mode 100644 (file)
index 0000000..51ec479
Binary files /dev/null and b/images/tabs/highlighted/star-orange.png differ
diff --git a/images/tabs/highlighted/star-orange@2x.png b/images/tabs/highlighted/star-orange@2x.png
new file mode 100644 (file)
index 0000000..6ba522d
Binary files /dev/null and b/images/tabs/highlighted/star-orange@2x.png differ
diff --git a/images/tabs/history-normal.png b/images/tabs/history-normal.png
new file mode 100644 (file)
index 0000000..1081a76
Binary files /dev/null and b/images/tabs/history-normal.png differ
diff --git a/images/tabs/history-normal@2x.png b/images/tabs/history-normal@2x.png
new file mode 100644 (file)
index 0000000..4482274
Binary files /dev/null and b/images/tabs/history-normal@2x.png differ
diff --git a/images/tabs/library-normal.png b/images/tabs/library-normal.png
new file mode 100644 (file)
index 0000000..494cbf9
Binary files /dev/null and b/images/tabs/library-normal.png differ
diff --git a/images/tabs/library-normal@2x.png b/images/tabs/library-normal@2x.png
new file mode 100644 (file)
index 0000000..b707083
Binary files /dev/null and b/images/tabs/library-normal@2x.png differ
diff --git a/images/tabs/search-normal.png b/images/tabs/search-normal.png
new file mode 100644 (file)
index 0000000..9e1db28
Binary files /dev/null and b/images/tabs/search-normal.png differ
diff --git a/images/tabs/search-normal@2x.png b/images/tabs/search-normal@2x.png
new file mode 100644 (file)
index 0000000..205ab1b
Binary files /dev/null and b/images/tabs/search-normal@2x.png differ
diff --git a/images/tabs/star-normal.png b/images/tabs/star-normal.png
new file mode 100644 (file)
index 0000000..52e5a1c
Binary files /dev/null and b/images/tabs/star-normal.png differ
diff --git a/images/tabs/star-normal@2x.png b/images/tabs/star-normal@2x.png
new file mode 100644 (file)
index 0000000..ef35f6b
Binary files /dev/null and b/images/tabs/star-normal@2x.png differ
diff --git a/images/toolbar/add-gray.png b/images/toolbar/add-gray.png
new file mode 100644 (file)
index 0000000..200e8ec
Binary files /dev/null and b/images/toolbar/add-gray.png differ
diff --git a/images/toolbar/add-gray@2x.png b/images/toolbar/add-gray@2x.png
new file mode 100644 (file)
index 0000000..d2810ef
Binary files /dev/null and b/images/toolbar/add-gray@2x.png differ
diff --git a/images/toolbar/add.png b/images/toolbar/add.png
new file mode 100644 (file)
index 0000000..01ada21
Binary files /dev/null and b/images/toolbar/add.png differ
diff --git a/images/toolbar/add@2x.png b/images/toolbar/add@2x.png
new file mode 100644 (file)
index 0000000..96a583c
Binary files /dev/null and b/images/toolbar/add@2x.png differ
diff --git a/images/toolbar/download-gray.png b/images/toolbar/download-gray.png
new file mode 100644 (file)
index 0000000..b515d49
Binary files /dev/null and b/images/toolbar/download-gray.png differ
diff --git a/images/toolbar/download-gray@2x.png b/images/toolbar/download-gray@2x.png
new file mode 100644 (file)
index 0000000..faa8006
Binary files /dev/null and b/images/toolbar/download-gray@2x.png differ
diff --git a/images/toolbar/download.png b/images/toolbar/download.png
new file mode 100644 (file)
index 0000000..d96bd6c
Binary files /dev/null and b/images/toolbar/download.png differ
diff --git a/images/toolbar/download@2x.png b/images/toolbar/download@2x.png
new file mode 100644 (file)
index 0000000..8160af4
Binary files /dev/null and b/images/toolbar/download@2x.png differ
diff --git a/images/toolbar/file-gray.png b/images/toolbar/file-gray.png
new file mode 100644 (file)
index 0000000..779214a
Binary files /dev/null and b/images/toolbar/file-gray.png differ
diff --git a/images/toolbar/file-gray@2x.png b/images/toolbar/file-gray@2x.png
new file mode 100644 (file)
index 0000000..c4a1206
Binary files /dev/null and b/images/toolbar/file-gray@2x.png differ
diff --git a/images/toolbar/file.png b/images/toolbar/file.png
new file mode 100644 (file)
index 0000000..0b00209
Binary files /dev/null and b/images/toolbar/file.png differ
diff --git a/images/toolbar/file@2x.png b/images/toolbar/file@2x.png
new file mode 100644 (file)
index 0000000..b33c991
Binary files /dev/null and b/images/toolbar/file@2x.png differ
diff --git a/images/toolbar/refresh-gray.png b/images/toolbar/refresh-gray.png
new file mode 100644 (file)
index 0000000..09b4403
Binary files /dev/null and b/images/toolbar/refresh-gray.png differ
diff --git a/images/toolbar/refresh-gray@2x.png b/images/toolbar/refresh-gray@2x.png
new file mode 100644 (file)
index 0000000..78b470c
Binary files /dev/null and b/images/toolbar/refresh-gray@2x.png differ
diff --git a/images/toolbar/refresh-new.png b/images/toolbar/refresh-new.png
new file mode 100644 (file)
index 0000000..fd4c2a2
Binary files /dev/null and b/images/toolbar/refresh-new.png differ
diff --git a/images/toolbar/refresh-new@2x.png b/images/toolbar/refresh-new@2x.png
new file mode 100644 (file)
index 0000000..35130bc
Binary files /dev/null and b/images/toolbar/refresh-new@2x.png differ
diff --git a/images/toolbar/refresh-orange.png b/images/toolbar/refresh-orange.png
new file mode 100755 (executable)
index 0000000..f462f2b
Binary files /dev/null and b/images/toolbar/refresh-orange.png differ
diff --git a/images/toolbar/refresh-orange@2x.png b/images/toolbar/refresh-orange@2x.png
new file mode 100755 (executable)
index 0000000..46aef1d
Binary files /dev/null and b/images/toolbar/refresh-orange@2x.png differ
diff --git a/images/toolbar/refresh.png b/images/toolbar/refresh.png
new file mode 100644 (file)
index 0000000..f1fdf7a
Binary files /dev/null and b/images/toolbar/refresh.png differ
diff --git a/images/toolbar/refresh@2x.png b/images/toolbar/refresh@2x.png
new file mode 100644 (file)
index 0000000..72bdbb9
Binary files /dev/null and b/images/toolbar/refresh@2x.png differ
diff --git a/images/win/daemon_down.ico b/images/win/daemon_down.ico
new file mode 100644 (file)
index 0000000..75cfe29
Binary files /dev/null and b/images/win/daemon_down.ico differ
diff --git a/images/win/daemon_up.ico b/images/win/daemon_up.ico
new file mode 100644 (file)
index 0000000..1ab0064
Binary files /dev/null and b/images/win/daemon_up.ico differ
diff --git a/images/win/notification.ico b/images/win/notification.ico
new file mode 100644 (file)
index 0000000..01b1819
Binary files /dev/null and b/images/win/notification.ico differ
diff --git a/images/win/seafile_auto_sync_disabled.ico b/images/win/seafile_auto_sync_disabled.ico
new file mode 100644 (file)
index 0000000..71ad900
Binary files /dev/null and b/images/win/seafile_auto_sync_disabled.ico differ
diff --git a/images/win/seafile_transfer_1.ico b/images/win/seafile_transfer_1.ico
new file mode 100644 (file)
index 0000000..30da92b
Binary files /dev/null and b/images/win/seafile_transfer_1.ico differ
diff --git a/images/win/seafile_transfer_2.ico b/images/win/seafile_transfer_2.ico
new file mode 100644 (file)
index 0000000..057b8a0
Binary files /dev/null and b/images/win/seafile_transfer_2.ico differ
diff --git a/images/win/seafile_warning.ico b/images/win/seafile_warning.ico
new file mode 100644 (file)
index 0000000..50f3e47
Binary files /dev/null and b/images/win/seafile_warning.ico differ
diff --git a/qt-linux.css b/qt-linux.css
new file mode 100644 (file)
index 0000000..8a1c51d
--- /dev/null
@@ -0,0 +1,4 @@
+
+PrivateShareDialog QFrame#mFrame {
+    border: 0;
+}
\ No newline at end of file
diff --git a/qt-mac.css b/qt-mac.css
new file mode 100644 (file)
index 0000000..03de63d
--- /dev/null
@@ -0,0 +1,43 @@
+QToolButton#mDownloadTasksBtn,
+QToolButton#mServerStatusBtn
+{
+    border-style:flat;
+}
+
+/* QToolButton:hover */
+/* { */
+/*     border: 1px solid #ccc; */
+/*     border-radius: 4px; */
+/*     background-color: rgb(255,255,255); */
+/* } */
+
+/*
+DownloadRepoDialog {
+    min-height: 400px;
+    max-height: 400px;
+}
+*/
+
+QToolButton#mAccountBtn
+{
+    margin-right: 0px;
+}
+
+
+QFrame#mFrame
+{
+    border: 0;
+}
+
+FileBrowserDialog QToolBar QToolButton#backwardButton {
+    margin-right: 0px;
+}
+
+FileBrowserDialog QToolBar QToolButton#forwardButton {
+    margin-left: 0px;
+}
+
+SyncErrorsDialog QWidget#mainWidget {
+    border : 0;
+    border-radius: 0px;
+}
diff --git a/qt-win.css b/qt-win.css
new file mode 100644 (file)
index 0000000..164064b
--- /dev/null
@@ -0,0 +1,19 @@
+QLabel {
+    font-family: Microsoft YaHei;
+}
+
+QFrame#mFrame {
+    background-color: white;
+}
+
+RepoTreeView {
+    font-family: Microsoft YaHei;
+}
+
+FileTableView QHeaderView::section:first {
+    padding-left: 36px;
+}
+
+SyncErrorsTableView::item {
+    padding-left: 2px;
+}
diff --git a/qt.css b/qt.css
new file mode 100644 (file)
index 0000000..b944e74
--- /dev/null
+++ b/qt.css
@@ -0,0 +1,710 @@
+QWidget#mainWrapper {
+    min-width: 320px;
+    min-height: 583px;
+    border: 1px solid #333;
+    border-radius: 5px;
+    background: #F5F5F7;
+}
+
+QLabel {
+    font-family: Arial;
+}
+
+CloudView {
+    min-width: 300px;
+    /* max-width: 300px; */
+    min-height: 450px;
+}
+
+QToolButton#mAccountBtn
+{
+    margin: 0;
+    padding: 0;
+    border: 0;
+}
+
+QToolButton#mAccountBtn:selected,
+QToolButton#mAccountBtn:hover {
+    background: #f8f8f8;
+}
+
+CloudView QToolBar {
+    border: 0;
+    /* max-width: 290px; */
+    border-bottom: 1px solid #DCDCDE;
+}
+
+CloudView QToolBar QWidget#spacerWidget {
+    min-width: 6px;
+    max-width: 6px;
+}
+
+QToolBar QAbstractButton {
+    margin-left: 10px;
+}
+
+RepoDetailDialog {
+    min-width: 400px;
+    min-height: 250px;
+}
+
+CloudView QLabel#mEmail {
+    font-family: Arial;
+    font-size: 15px;
+    color: #525252;
+}
+
+CloudView QLabel#mServerAddr {
+    font-family: Arial;
+    color: #A4A4A4;
+    font-size: 13px;
+}
+
+QDialog QLabel#mTitle {
+    color: #F89A01;
+    font-family: Arial;
+    font-size: 20px;
+}
+
+QToolButton#mSeahubMessagesBtn:selected,
+QToolButton#mSeahubMessagesBtn:hover {
+    background: white;
+}
+
+QWidget#mHeader {
+    min-height: 26px;
+    max-height: 26px;
+}
+
+QWidget#mHeader QPushButton {
+    padding: 5px;
+    padding-bottom: 0;
+    border: 0;
+    qproperty-focusPolicy: NoFocus;
+}
+
+QWidget#mHeader QPushButton:hover {
+    color: #FF9A2A;
+    padding-top: 3px;
+    margin-top: 1px;
+    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+                                stop: 0 #A1A1A2,
+                                stop: 1 #F5F5F7);
+}
+
+QWidget#mHeader QPushButton#mCloseBtn:hover {
+    border-top-right-radius: 5px;
+    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+                                stop: 0 #FF9A2A,
+                                stop: 1 #FEEAEA);
+}
+
+QWidget#mHeader QLabel#mBrand,
+QWidget#mHeader QLabel#mLogo {
+    margin-top: 6px;
+    margin-right: 4px;
+    font-size: 14px;
+    font-family: Arial;
+}
+
+RepoTreeView
+{
+    background: white;
+    border: 0;
+    font-size: 14px;
+    /* border-top: 1px solid #DCDCDE; */
+    /* border-bottom: 1px solid #DCDCDE; */
+    padding-top: 8px;
+}
+
+QLineEdit#mSearchBar {
+    min-height: 30px;
+    max-height: 30px;
+    margin-left: 16px;
+    margin-right: 16px;
+    margin-top: 0;
+    margin-bottom: 0px;
+    padding: 0 0px;
+    border: 1px solid #E0E0E0;
+    border-radius: 3px;
+}
+
+QLineEdit#mSearchBar QLabel {
+    text-align: center;
+    margin-left: 16px;
+    margin-right: 16px;
+}
+
+QLineEdit#mSearchBar:focus {
+    color: #525252;
+}
+
+
+RepoTreeView QScrollBar {
+    margin-right: 1px;
+}
+
+CloudView QWidget#mDropArea {
+    min-height: 54px;
+    max-height: 54px;
+    background: #F9F9F9;
+    padding: 0;
+    padding-top: 10px;
+}
+
+CloudView QFrame#mDropInner {
+    min-width: 280px;
+    /* max-width: 280px; */
+    min-height: 50px;
+    max-height: 50px;
+    border: 1.5px dashed #E4E4E4;
+    border-radius: 3px;
+    padding: 0px 0;
+}
+
+CloudView QFrame#mDropInner QLabel {
+    font-family: Arial;
+}
+
+CloudView QPushButton#mSelectFolderBtn {
+    min-height: 26px;
+    max-height: 26px;
+    font-size: 14px;
+    font-family: Arial;
+    border: 1px solid #C5C5C5;
+    border-radius: 3px;
+    color: #4A4A4A;
+    background: #F5F5F7;
+    qproperty-focusPolicy: NoFocus;
+    qproperty-flat: true;
+    padding-right: 15px;
+    padding-left: 15px;
+    margin: 0;
+}
+
+CloudView QPushButton#mSelectFolderBtn:hover {
+    font-size: 14px;
+    font-weight: ;
+    background: #DBDBDC;
+    border-radius: 3px;
+}
+
+CloudView QLabel#mDropFolderText {
+    color: #888888;
+    font-size: 14px;
+    margin-left: 3px;
+}
+
+CloudView QFrame#mFooter {
+    border: 0;
+    min-height: 28px;
+    max-height: 28px;
+    margin-bottom: 2px;
+    padding: 0;
+    padding-bottom: 0px;
+    padding-right: 0px;
+    background: #F9F9F9;
+}
+
+CloudView QFrame#mFooter QLabel#mDownloadTasksInfo,
+CloudView QFrame#mFooter QLabel#mDownloadRate,
+CloudView QFrame#mFooter QLabel#mUploadRate
+{
+    color: #999999;
+    font-size: 10px;
+    min-height: 14px;
+    max-height: 14px;
+    margin-bottom: 0px;
+    min-width: 50px;
+    /* max-width: 80px; */
+}
+
+CloudView QFrame#mFooter QLabel#mUploadRateArrow,
+CloudView QFrame#mFooter QLabel#mDownloadRateArrow
+{
+    min-height: 10px;
+    max-height: 10px;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    margin-right: 0px;
+    margin-left: 5px;
+}
+
+CloudView QFrame#mFooter QLabel#mDownloadRateArrow
+{
+    margin-right: 0px;
+}
+
+
+CreateRepoDialog {
+    min-width: 550px;
+    min-height: 247px;
+    max-height: 247px;
+}
+
+CreateRepoDialog QLabel#mDesc {
+    min-height: 60px;
+}
+
+QFrame#mFooter QToolButton#mServerStatusBtn,
+QFrame#mFooter QToolButton#mDownloadTasksBtn {
+    margin-top: 0px;
+    qproperty-focusPolicy: NoFocus;
+}
+
+QFrame#mFooter QToolButton#mServerStatusBtn {
+    margin-left: 10px;
+    alignment: left;
+}
+
+ServerStatusDialog QListView {
+    qproperty-focusPolicy: NoFocus;
+}
+
+ServerStatusDialog QListView:item {
+    margin-bottom: 4px;
+}
+
+UninstallHelperDialog {
+    min-width: 400px;
+    /* max-width: 400px; */
+    min-height: 100px;
+    max-height: 100px;
+}
+
+CloudView QSizeGrip {
+    margin-right: 2px;
+}
+
+InitVirtualDriveDialog QLabel#mStatusText {
+    font-size: 16px;
+    font-family: Arial;
+    padding-right: 20px;
+    qproperty-wordWrap: true;
+    min-width: 350px;
+}
+
+InitVirtualDriveDialog QLabel#mStatusIcon {
+    min-width: 48px;
+    max-width: 48px;
+    margin-left: 60px;
+    margin-right: 20px;
+}
+
+QLabel#loadingFailedText {
+    color: #777;
+    font-size: 16px;
+    margin-top: -120px;
+    qproperty-wordWrap: true;
+}
+
+SettingsDialog {
+    min-width: 560px;
+    max-width: 560px;
+
+    min-height: 390px;
+    max-height: 390px;
+}
+
+SettingsDialog QTabWidget::pane QLabel#desc,
+SettingsDialog QTabWidget::pane QLabel#desc_2
+{
+    font-size: 12px;
+    color: #555;
+    padding-left: 20px;
+}
+
+LoginDialog QLabel#hint,
+LoginDialog QLabel#hint_1,
+LoginDialog QLabel#hint_2,
+LoginDialog QLabel#hint_3
+{
+    font-size: 12px;
+    color: #555;
+}
+
+ShibLoginDialog QLineEdit#addressText {
+    min-height: 25px;
+    margin: 0px;
+    padding: 0 4px;
+    border: 1px solid #BCBCBE;
+    border-radius: 3px;
+}
+
+SslConfirmDialog {
+    min-width: 400px;
+    min-height: 200px;
+}
+
+SslConfirmDialog QLabel#mHint {
+    margin-right: 20px;
+}
+
+SslConfirmDialog QCheckBox#mRememberChoiceCheckBox {
+    min-height: 40px;
+    max-height: 40px;
+    margin-bottom: 5px;
+    /* border: 1px solid black; */
+}
+
+DownloadRepoDialog QLabel#mRepoName {
+    font-size: 16px;
+    margin-bottom: 8px;
+}
+
+DownloadRepoDialog QLabel#mMergeHint {
+    font-size: 12px;
+}
+
+DownloadRepoDialog QLabel#mRepoIcon {
+    min-width: 36px;
+    max-width: 36px;
+    min-height: 36px;
+    max-height: 36px;
+    margin-right: 10px;
+    margin-bottom: 8px;
+}
+
+DownloadRepoDialog QPushButton#mSwitchToSyncBtn {
+}
+
+SeafileTabWidget {
+    border: 0;
+    margin: 0;
+}
+
+SeafileTabBar {
+    alignment: left;
+    border: 0;
+}
+
+SeafileTabBar::tab {
+    background: white;
+
+    min-height: 36px;
+    max-height: 36px;
+
+    min-width: 100px;
+
+    padding: 0;
+    border: 0;
+}
+
+StarredFilesListView {
+    border-top: 1px solid #DCDCDE;
+}
+
+QWidget#EmptyPlaceHolder,
+LoadingView
+{
+    border-top: 1px solid #DCDCDE;
+}
+
+QWidget#EventsContainerView {
+    margin: 0;
+    border: 0;
+    border-top: 1px solid #DCDCDE;
+}
+
+QWidget#EventsContainerView LoadingView,
+QWidget#EventsContainerView QToolButton
+{
+    max-height: 40px;
+    min-height: 40px;
+}
+
+QWidget#EventsContainerView LoadingView {
+    /* border: 1px solid red; */
+    border: 0;
+    background: white;
+    margin: 0;
+}
+
+EventsListView {
+    border: 0;
+    border-top: 1px solid #DCDCDE;
+}
+
+EventDetailsDialog {
+    margin: 20px;
+    min-width: 300px;
+    min-height: 300px;
+}
+
+EventDetailsListView
+{
+    background: white;
+    border: 0;
+    font-size: 16px;
+    border-top: 1px solid #DCDCDE;
+}
+
+EventDetailsListView {
+    qproperty-iconSize: 36px;
+}
+
+EventDetailsListView QScrollBar {
+    margin-right: 1px;
+}
+
+ActivitiesTab, EventsListView
+{
+    qproperty-focusPolicy: NoFocus;
+}
+
+FileBrowserDialog {
+    margin: 0;
+    min-width: 640px;
+    min-height: 456px;
+}
+
+FileBrowserDialog QToolBar#topBar {
+    border: 0;
+    border-bottom: 1px solid #d0d0d0;
+    padding: 0;
+    min-height: 42px;
+    background: #F5F5F7;
+    spacing: 0;
+}
+
+FileBrowserDialog QToolBar QPushButton {
+    font-size: 13px;
+    padding: 3px;
+    margin: 1px;
+    background-color: white;
+    qproperty-focusPolicy: NoFocus;
+}
+
+FileBrowserDialog QToolBar QWidget#goHomeButton {
+    border: 0;
+    margin: 0;
+    padding: 0;
+    padding-left: 3px;
+    margin-right: -7px;
+}
+
+FileBrowserDialog QToolBar QToolButton#backwardButton {
+    border: 0;
+}
+
+FileBrowserDialog QToolBar QToolButton#forwardButton {
+    border: 0;
+}
+
+FileBrowserDialog QToolBar QLabel {
+    margin-left: 2px;
+}
+
+FileBrowserDialog QToolBar QPushButton:hover {
+    border: 1px solid #d0d0d0;
+    border-radius: 4px;
+    color: #FF9A2A;
+}
+
+FileTableView {
+    border: 0;
+    margin: 0;
+    padding-left: 0px;
+    border-bottom: 1px solid #e0e0e0;
+    background-color: white;
+    qproperty-focusPolicy: NoFocus;
+}
+
+FileTableView QHeaderView::section,
+FileBrowserSearchView QHeaderView::section{
+    border: 0;
+    padding: 8px;
+    outline: 0px;
+    color: #b3b3b3;
+    background-color: white;
+    font-size: 12px;
+    padding-top: 20px;
+}
+
+FileTableView QHeaderView::section:first,
+FileBrowserSearchView QHeaderView::section:first{
+    padding-left: 40px;
+}
+
+FileTableView QHeaderView::down-arrow,
+FileBrowserSearchView QHeaderView::down-arrow{
+    width: 15px;
+    height: 5px;
+    padding-top: 15px;
+    subcontrol-position: center right;
+}
+
+FileTableView QHeaderView::up-arrow,
+FileBrowserSearchView QHeaderView::up-arrow{
+    padding-top: 15px;
+    subcontrol-position: center right;
+}
+
+FileTableView QHeaderView::down-arrow,
+FileBrowserSearchView QHeaderView::down-arrow{
+  image: url(:/images/filebrowser/down-arrow.png);
+}
+
+FileTableView QHeaderView::up-arrow,
+FileBrowserSearchView QHeaderView::up-arrow{
+  image: url(:/images/filebrowser/up-arrow.png);
+}
+
+FileTableView::item,
+FileBrowserSearchView::item{
+    border-top: 1px solid #e0e0e0;
+}
+
+FileTableView::item :last,
+FileBrowserSearchView::item :last{
+    padding-right: 13px;
+}
+
+FileBrowserDialog QWidget#statusBar {
+    padding: 0px;
+    margin: 0px;
+    min-height: 36px;
+    max-height: 36px;
+    background: #F5F5F7;
+}
+
+FileBrowserDialog QToolButton#uploadButton {
+    border: 0;
+    padding: 0px;
+    margin-left: 15px;
+}
+
+FileBrowserDialog QToolButton#refreshButton {
+    border: 0;
+    margin-right: 15px;
+}
+
+FileBrowserProgressDialog {
+    min-width: 320px;
+    max-width: 420px;
+}
+
+SeafileTabWidget QWidget#pane {
+    background-color: white;
+}
+
+SharedLinkDialog QLabel {
+    font-size: 12px;
+}
+
+SharedLinkDialog QCheckBox {
+    font-size: 10px;
+}
+
+SeafileLinkDialog QLabel {
+    font-size: 12px;
+}
+
+SeafileLinkDialog QCheckBox {
+    font-size: 10px;
+}
+
+SearchResultListView {
+    border-top: 1px solid #DCDCDE;
+    border-bottom: 1px solid #DCDCDE;
+}
+
+QProgressBar#mStorageUsage {
+    min-width: 60px;
+    max-width: 60px;
+    max-height: 6px;
+    min-height: 6px;
+    border: 1px solid #DBDBDC;
+    border-radius: 1px;
+    text-align: right;
+    margin-top: 0px;
+    margin-left: 0px;
+    margin-right: 0;
+    font-size: 11px;
+}
+
+PrivateShareDialog {
+    min-width: 550px;
+    min-height: 200px;
+}
+
+/* PrivateShareDialog QLabel#mStatusText { */
+/*     padding-left: 1px; */
+/* } */
+
+PrivateShareDialog QLineEdit#mUsernameInputBar {
+    padding-left: 4px;
+}
+
+SharedItemsTableView {
+    margin-top: 10px;
+    qproperty-focusPolicy: NoFocus;
+}
+
+SharedItemsTableView QHeaderView::section {
+    /* outline: 1px; */
+    font-size: 12px;
+    padding-top: 10px;
+    font-family: Arial;
+}
+
+SyncErrorsDialog {
+    margin: 0;
+    min-width: 700px;
+    min-height: 300px;
+}
+
+SyncErrorsTableView {
+    border: 0;
+    margin: 0;
+    padding-left: 14px;
+    padding-right: 14px;
+    border-bottom: 1px solid #e0e0e0;
+    background-color: white;
+    qproperty-focusPolicy: NoFocus;
+}
+
+SyncErrorsTableView QHeaderView::section {
+    border: 0;
+    padding: 8px;
+    padding-left: 5px;
+    outline: 0px;
+    color: #b3b3b3;
+    background-color: white;
+    font-size: 12px;
+    padding-top: 20px;
+}
+
+SyncErrorsTableView::item {
+    padding-top: 5px;
+    padding-left: 0px;
+    border-top: 1px solid #e0e0e0;
+}
+
+SyncErrorsTableView::item :last {
+    padding-right: 13px;
+}
+
+SyncErrorsTableView::item:selected {
+    background-color: #F9E0C7;
+}
+
+LoadMoreButton QToolButton#loadMoreBtn {
+    padding: 0;
+    font-family: Arial;
+    font-size: 14px;
+    qproperty-focusPolicy: NoFocus;
+    /* text-decoration: underline; */
+    color: #626262;
+    border: 0;
+    border-radius: 18px;
+    /* border-top: 1px solid #eee; */
+    background-color: #EFEEEE;
+    width: 120px;
+    height: 34px;
+}
+
+SeafileTabWidget QToolButton:hover {
+    border: 0;
+    border-radius: 0;
+}
diff --git a/scripts/build.py b/scripts/build.py
new file mode 100755 (executable)
index 0000000..4c4bacc
--- /dev/null
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+import sys, os, shutil
+import build_helper
+import argparse
+
+target='seafile-applet'
+num_cpus=str(build_helper.num_cpus)
+configuration = 'Release'
+
+def postbuild_copy_libraries():
+    print 'copying dependent libraries...'
+    if sys.platform == 'darwin':
+        postbuild_copy_libraries_xcode()
+    else:
+        postbuild_copy_libraries_posix()
+
+def postbuild_copy_libraries_posix():
+    lib_path = os.path.join(target, 'lib')
+    bin_path = os.path.join(target, 'bin')
+    binaries = [os.path.join(bin_path, target),
+                os.path.join(bin_path, 'ccnet'),
+                os.path.join(bin_path, 'seaf-daemon')]
+    libs = []
+    for binrary in binaries:
+        libs.extend(build_helper.get_dependencies_recursively(binrary))
+    if not os.path.isdir(lib_path):
+        os.makedirs(lib_path)
+    for lib in libs:
+        shutil.copyfile(lib, lib_path + '/' + os.path.basename(lib))
+
+def postbuild_copy_libraries_xcode():
+    frameworks_path = os.path.join(target + '.app', 'Contents', 'Frameworks')
+    resources_path = os.path.join(target + '.app', 'Contents', 'Resources')
+    macos_path = os.path.join(target + '.app', 'Contents', 'MacOS')
+    binaries = [os.path.join(macos_path, target),
+                os.path.join(resources_path, 'ccnet'),
+                os.path.join(resources_path, 'seaf-daemon')]
+    libs = []
+    for binrary in binaries:
+        libs.extend(build_helper.get_dependencies_recursively(binrary))
+    if not os.path.isdir(frameworks_path):
+        os.makedirs(frameworks_path)
+    for lib in libs:
+        shutil.copyfile(lib, frameworks_path + '/' + os.path.basename(lib))
+    build_helper.write_output(['macdeployqt', target + '.app'])
+
+def postbuild_fix_rpath():
+    print 'fixing rpath...'
+    if os.name == 'winnt':
+        print 'not need to fix rpath'
+    elif sys.platform == 'linux':
+        postbuild_patchelf()
+    elif sys.platform == 'darwin':
+        postbuild_install_name_tool()
+    else:
+        print 'not supported in platform %s' % sys.platform
+    print 'fixing rpath...done'
+
+def postbuild_install_name_tool():
+    frameworks_path = os.path.join(target + '.app', 'Contents', 'Frameworks')
+    resources_path = os.path.join(target + '.app', 'Contents', 'Resources')
+    macos_path = os.path.join(target + '.app', 'Contents', 'MacOS')
+    binaries = [os.path.join(macos_path, target),
+                os.path.join(resources_path, 'ccnet'),
+                os.path.join(resources_path, 'seaf-daemon')]
+    for binary in binaries:
+        build_helper.write_output(['install_name_tool', '-add_rpath', '@executable_path/../Frameworks', binary])
+        deps = build_helper.get_dependencies(binary)
+        for dep in deps:
+                build_helper.write_output(['install_name_tool', '-change', dep, '@executable_path/../Frameworks/%s' % os.path.basename(dep), binary])
+        build_helper.write_output(['install_name_tool', '-delete_rpath', '/usr/local/lib', binary])
+        build_helper.write_output(['install_name_tool', '-delete_rpath', '/opt/local/lib', binary])
+    libs = os.listdir(frameworks_path)
+    for lib_name in libs:
+        lib = os.path.join(frameworks_path, lib_name)
+        if os.path.isdir(lib):
+            continue
+        build_helper.write_output(['install_name_tool', '-id', '@loader_path/../Frameworks/%s' % os.path.basename(lib), lib])
+        build_helper.write_output(['install_name_tool', '-add_rpath', '@loader_path/../Frameworks', lib])
+        build_helper.write_output(['install_name_tool', '-delete_rpath', '/usr/local/lib', lib])
+        build_helper.write_output(['install_name_tool', '-delete_rpath', '/opt/local/lib', lib])
+        deps = build_helper.get_dependencies(lib)
+        for dep in deps:
+                build_helper.write_output(['install_name_tool', '-change', dep, '@loader_path/../Frameworks/%s' % os.path.basename(dep), lib])
+
+def postbuild_patchelf():
+    lib_path = os.path.join(target, 'lib')
+    bin_path = os.path.join(target, 'bin')
+    binaries = os.listdir(bin_path)
+    for binrary_name in binaries:
+        binrary = os.path.join(bin_path, binrary_name)
+        if os.path.isdir(binrary):
+            continue
+        build_helper.write_output(['patchelf', '-set-rpath', '\\\$ORIGIN/../lib', binrary])
+    libs = os.listdir(lib_path)
+    for lib_name in libs:
+        lib = os.path.join(lib_path, lib_name)
+        if os.path.isdir(lib):
+            continue
+        build_helper.write_output(['patchelf', '-set-rpath', '\\\$ORIGIN/../lib', lib])
+
+def execute_buildscript(generator = 'xcode'):
+    print 'executing build scripts...'
+    if generator == 'xcode':
+        command = ['xcodebuild', '-target', 'ALL_BUILD', '-configuration', configuration, '-jobs', num_cpus]
+    elif generator == 'ninja':
+        command = ['ninja']
+    else:
+        command = ['make', '-j', num_cpus]
+    build_helper.write_output(command)
+    if generator == 'xcode':
+        shutil.copytree(os.path.join(configuration, target+ '.app'), target + '.app')
+
+
+def generate_buildscript(generator = 'xcode', os_min = '10.7', with_shibboleth = False):
+    print 'generating build scripts...'
+    if not os.path.exists('CMakeLists.txt'):
+        print 'Please execute this frome the top dir of the source'
+        sys.exit(-1)
+    cmake_args = ['cmake', '.', '-DCMAKE_BUILD_TYPE=' + configuration]
+    cmake_args.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=' + os_min);
+    if with_shibboleth:
+        cmake_args.append('-DBUILD_SHIBBOLETH_SUPPORT=ON')
+    else:
+        cmake_args.append('-DBUILD_SHIBBOLETH_SUPPORT=OFF')
+    if generator == 'xcode':
+        cmake_args.extend(['-G', 'Xcode'])
+    elif generator == 'ninja':
+        cmake_args.extend(['-G', 'Ninja'])
+    else:
+        cmake_args.extend(['-G', 'Unix Makefiles'])
+    build_helper.write_output(cmake_args)
+
+def prebuild_cleanup(Force=False):
+    print 'cleaning up previous files...'
+    if Force:
+        build_helper.write_output(['git', 'clean', '-xfd'])
+        return
+    shutil.rmtree(configuration, ignore_errors=True)
+    shutil.rmtree('CMakeFiles', ignore_errors=True)
+    shutil.rmtree(target+ '.app', ignore_errors=True)
+    if os.path.exists ('CMakeCache.txt'):
+        os.remove('CMakeCache.txt')
+
+if __name__ == '__main__':
+    if sys.platform != 'darwin':
+        print 'Only support Mac OS X Platfrom!'
+        exit(-1)
+
+    parser = argparse.ArgumentParser(description='Script to build Seafile Client and package it')
+    parser.add_argument('--build_type', '-t', help='build type', default='Release')
+    parser.add_argument('--os_min', '-m', help='osx deploy version', default='10.7')
+    parser.add_argument('--with_shibboleth', help='build with shibboleth support', action='store_true')
+    parser.add_argument('--output', '-o', help='output file', default='-')
+    parser.add_argument('--clean', '-c', help='clean forcely', action='store_true')
+    args = parser.parse_args()
+
+    if args.build_type == 'Debug' or args.build_type == 'debug':
+        configuration = 'Debug'
+
+    print 'build with type %s' % configuration
+
+    os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
+
+    prebuild_cleanup(Force=args.clean)
+
+    if args.output == '-':
+        build_helper.set_output(sys.stdout)
+    else:
+        output = open(args.output, 'wb')
+        build_helper.set_output(output)
+
+    generate_buildscript(os_min=args.os_min, with_shibboleth=args.with_shibboleth)
+    execute_buildscript()
+    postbuild_copy_libraries()
+    postbuild_fix_rpath()
+
+    build_helper.close_output()
diff --git a/scripts/build_breakpad.sh b/scripts/build_breakpad.sh
new file mode 100755 (executable)
index 0000000..464f070
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+set -e
+
+PWD=$(dirname "${BASH_SOURCE[0]}")
+
+## get a copy of breakpad if not exist
+if [ ! -d $PWD/../third_party/breakpad ]; then
+  pushd $PWD/../third_party
+  git clone https://github.com/Chilledheart/breakpad.git
+  popd
+fi
+
+## get a copy of gyp if not exist
+if [ ! -d $PWD/../third_party/gyp ]; then
+  pushd $PWD/../third_party
+  git clone https://chromium.googlesource.com/external/gyp.git
+  popd
+fi
+
+## build breakpad
+pushd $PWD/../third_party/breakpad
+
+GYP_GENERATORS=ninja ../gyp/gyp --depth .
+if [ -d out/Debug_Base ]; then
+  ninja -C out/Debug_Base
+elif [ -d out/Default ]; then
+  ninja -C out/Default
+else
+  echo "unable to find build.ninja, exiting"
+fi
+
+echo "breakpad was built successfuly"
+echo "now you can set up your PATH_TO_BREAKPAD_ROOT to $(pwd)"
+
+popd
+
+
diff --git a/scripts/build_helper.py b/scripts/build_helper.py
new file mode 100755 (executable)
index 0000000..f7e79dc
--- /dev/null
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+import subprocess, sys, os
+import re
+from multiprocessing import cpu_count
+
+num_cpus=cpu_count()
+
+def get_dependencies_by_otool(path):
+    if path.endswith('.app') and os.path.isdir(path):
+        path = os.path.join(path, 'Contents', 'MacOS', os.path.basename(path))
+    lines = check_string_output(['otool', '-L', path]).split('\n')[1:]
+    outputs = []
+    if path.endswith('.dylib'):
+        outputs.append(path);
+
+    for line in lines:
+        name = line.split('(')[0].strip()
+        if name.startswith('@executable_path/'):
+            name = os.path.join(path, name[len('@executable_path/'):])
+        if name.startswith('@loader_path/'):
+            name = os.path.join(path, name[len('@loader_path/'):])
+        # todo: search rpath
+        if not name.startswith('/'):
+            continue
+        # skip system libraries
+        if name.startswith('/usr/lib') or name.startswith('/System'):
+            continue
+        # skip Frameworks (TODO: support frameworks, except Qt's framewroks)
+        if re.search(r'(\w+)\.framework/Versions/[A-Z0-9]/(\1)$', name):
+            continue
+        # if file not found
+        if not os.path.exists(name):
+            raise IOError('broken dependency: file %s not found' % name)
+        outputs.append(os.path.normpath(name))
+
+    return outputs
+
+def get_dependencies_by_ldd(path):
+    lines = check_string_output(['ldd', '-v', path]).split('Version information:')[1].split('\n\t')
+    outputs = []
+
+    for line in lines:
+        if not line.startswith('\t'):
+            continue
+        name = line.strip().split('=>')[1].strip()
+        # todo: search rpath
+        if name.startswith('$ORIGIN/'):
+            name = os.path.join(path, name[len('$ORIGIN/'):])
+        # skip system libraries, such as linux-vdso.so
+        if not name.startswith('/'):
+            continue
+        # skip system libraries, part2
+        if name.startswith('/usr/lib') or name.startswith('/usr/lib64'):
+            continue
+        # skip system libraries, part3
+        if name.startswith('/lib') or name.startswith('/lib64'):
+            continue
+        # if file not found
+        if not os.path.exists(name):
+            raise IOError('broken dependency: file %s not found' % name)
+        outputs.append(os.path.normpath(name))
+
+    # remove duplicate items
+    return list(set(outputs))
+
+def get_dependencies_by_objdump(path):
+    print 'todo'
+    return []
+
+def get_dependencies_by_dependency_walker(path):
+    print 'todo'
+    return []
+
+def get_dependencies(path):
+    if os.name == 'winnt':
+        return get_dependencies_by_objdump(path)
+    elif sys.platform == 'darwin':
+        return get_dependencies_by_otool(path)
+    elif sys.platform == 'linux':
+        return get_dependencies_by_ldd(path)
+    else:
+        raise IOError('not supported in platform %s' % sys.platform)
+
+def get_dependencies_recursively(path):
+    if os.name == 'winnt':
+        return get_dependencies_by_objdump(path)
+    elif sys.platform == 'darwin':
+        deps = get_dependencies_by_otool(path)
+        while(True):
+            deps_extened = list(deps)
+            for dep in deps:
+                deps_extened.extend(get_dependencies_by_otool(dep))
+            deps_extened = set(deps_extened)
+            if deps_extened != deps:
+                deps = deps_extened;
+            else:
+                return list(deps_extened)
+    elif sys.platform == 'linux':
+        return get_dependencies_by_ldd(path)
+    else:
+        raise IOError('not supported in platform %s' % sys.platform)
+
+def check_string_output(command):
+    return subprocess.check_output(command, stderr=subprocess.STDOUT).decode().strip()
+
+_output = sys.stdout
+def set_output(output=sys.stdout):
+    global _output
+    _output = output
+
+def close_output():
+    if _output != sys.stdout:
+        _output.close()
+
+def write_output(command):
+    proc = subprocess.Popen(command, stdout=_output, stderr=_output, shell=False)
+    proc.communicate()
+
+if __name__ == '__main__':
+    if (len(sys.argv) < 2):
+        print 'Usage: %s <input-file>' % sys.argv[0]
+        sys.exit(-1)
+    print get_dependencies_recursively(sys.argv[1])
diff --git a/scripts/ci-build.sh b/scripts/ci-build.sh
new file mode 100755 (executable)
index 0000000..6842af8
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/bash
+set -x
+set -e
+PWD=$(dirname "${BASH_SOURCE[0]}")
+
+pushd $PWD/..
+
+if [ "$TRAVIS_OS_NAME" = "linux" ]; then
+    set +e
+    . /opt/qt56/bin/qt56-env.sh
+    set -e
+    cmake -DBUILD_TESTING=on -DBUILD_SHIBBOLETH_SUPPORT=$BUILD_SHIBBOLETH_SUPPORT .
+    make -j8 VERBOSE=1
+    make test VERBOSE=1
+elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
+    export PATH=/usr/local/opt/openssl/bin:/usr/local/opt/curl/bin:$PATH
+    export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig:/usr/local/opt/openssl/lib/pkgconfig:/usr/local/opt/sqlite/lib/pkgconfig
+    export CPPFLAGS="-I/usr/local/opt/openssl/include -I/usr/local/opt/sqlite/include -I/usr/local/opt/curl/include"
+    export CXXFLAGS="$CXXFLAGS $CPPFLAGS -I/usr/local/include"
+    export LDFLAGS="-L/usr/local/opt/openssl/lib -L/usr/local/opt/sqlite/lib -L/usr/local/opt/curl/lib -L/usr/local/lib"
+    export PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/Library/ENV/pkgconfig/10.9
+    export ACLOCAL_PATH=/usr/local/share/aclocal
+    cmake -G Xcode -DBUILD_TESTING=on .
+    xcodebuild -configuration Debug -target ALL_BUILD -jobs 8
+    xcodebuild -configuration Debug -target RUN_TESTS
+else
+    printf "not supported platform"
+    exit -1
+fi
+
+popd
diff --git a/scripts/genapp.sh b/scripts/genapp.sh
new file mode 100755 (executable)
index 0000000..5e39843
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -e
+
+build_file="build.py"
+
+print "WARNING: this file is deprecated."
+print "Please use $build_file instead"
+
+"$build_file" "$@"
diff --git a/scripts/install-deps-linux.sh b/scripts/install-deps-linux.sh
new file mode 100755 (executable)
index 0000000..357788e
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+set -x
+set -e
+PWD=$(dirname "${BASH_SOURCE[0]}")
+
+SEAFILE_BRANCH=master
+
+# Temporary fix
+sudo sed -i /rabbitmq\.com/d /etc/apt/sources.list
+sudo sed -i /rabbitmq\.com/d /etc/apt/sources.list.d/*.list
+
+sudo add-apt-repository -y ppa:smspillaz/cmake-2.8.12
+sudo apt-get update -qq
+sudo apt-get install -y valac uuid-dev libevent-dev re2c libjansson-dev cmake cmake-data
+
+sudo add-apt-repository -y ppa:beineri/opt-qt562-trusty
+sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
+sudo apt-get update -qq
+
+sudo apt-get install -y gcc-4.8 g++-4.8
+sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50
+sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50
+
+sudo apt-get install -y qt56base qt56translations qt56tools qt56webengine
+
+# Fix errors like:
+#
+#   CMake Error at /opt/qt56/lib/cmake/Qt5Gui/Qt5GuiConfigExtras.cmake:9 (message):
+#   Failed to find "GL/gl.h" in "/usr/include/libdrm"
+#
+# See https://github.com/Studio3T/robomongo/issues/1268
+sudo apt-get install -y mesa-common-dev libglu1-mesa-dev
+
+git clone --depth=1 --branch=master git://github.com/haiwen/libsearpc.git deps/libsearpc
+git clone --depth=1 --branch=master git://github.com/haiwen/ccnet.git deps/ccnet
+git clone --depth=1 --branch="$SEAFILE_BRANCH" git://github.com/haiwen/seafile.git deps/seafile
+pushd deps/libsearpc
+./autogen.sh && ./configure
+make -j8 && sudo make install
+popd
+
+pushd deps/ccnet
+./autogen.sh && ./configure --enable-client --disable-server
+make -j8 && sudo make install
+popd
+
+pushd deps/seafile
+./autogen.sh && ./configure --disable-fuse --disable-server --enable-client
+make -j8 && sudo make install
+popd
diff --git a/scripts/install-deps-osx.sh b/scripts/install-deps-osx.sh
new file mode 100755 (executable)
index 0000000..71579ca
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -x
+set -e
+## TODO: use the correct version of seafile for each branch
+
+brew up
+brew install qt4
+
+brew tap Chilledheart/seafile
+brew install --HEAD libsearpc ccnet seafile
diff --git a/scripts/strip-png.sh b/scripts/strip-png.sh
new file mode 100755 (executable)
index 0000000..3c3e77f
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Strip profiles and comments from png files.
+# This can avoid libpng warnings.
+# See https://wiki.archlinux.org/index.php/Libpng_errors
+
+[[ -x `which convert` ]] || {
+    echo
+    echo "Please install ImageMagick tool first".
+    echo
+    echo "On ubuntu: apt-get install imagemagick"
+    echo "On macos: port install ImageMagick"
+    echo
+}
+
+TOP_DIR=$(python -c "import os; print os.path.dirname(os.path.realpath('$0'))")/..
+
+find $TOP_DIR -type f -name \*.png -exec convert -strip {} {} \;
diff --git a/scripts/update-i18n.sh b/scripts/update-i18n.sh
new file mode 100755 (executable)
index 0000000..12590b3
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/env bash
+set -e
+
+PWD=$(dirname "${BASH_SOURCE[0]}")
+cd $PWD/..
+
+if [ ! -d .tx ]; then
+    echo "please make sure this script is under the scripts directory!"
+    exit -9
+fi
+
+if [ "$1" != "-v" ]; then
+    QUIET_FLAGS="-silent"
+fi
+
+function regenerate_source() {
+    if [ -f build.ninja ]; then
+        cmake -DBUILD_SHIBBOLETH_SUPPORT=on
+        ninja update-ts
+    elif [ -f Makefile ]; then
+        cmake -DBUILD_SHIBBOLETH_SUPPORT=on
+        make update-ts
+    else
+        local SEAFILE_PROJECT="seafile-client.pro"
+        rm -f $SEAFILE_PROJECT
+        qmake -project -o $SEAFILE_PROJECT
+        lrelease $SEAFILE_PROJECT $QUIET_FLAGS
+        lupdate $SEAFILE_PROJECT $QUIET_FLAGS
+        rm -f $SEAFILE_PROJECT
+    fi
+    find fsplugin -name "*.mm" | xargs genstrings -o fsplugin/en.lproj
+}
+
+function git_diff() {
+    set +e
+    git diff i18n/seafile_en.ts fsplugin/en.lproj
+    set -e
+}
+
+function push_source() {
+    tx push -s
+    pushd fsplugin
+    tx push -s
+    popd
+}
+
+function pull_translations() {
+    tx pull -a -f --minimum-perc=30
+    pushd fsplugin
+    tx pull -a -f --minimum-perc=80
+    popd
+}
+
+echo "This script will help you to regenerate sources of translations, "
+echo "update them to transifex and grab the latest translations from it"
+echo
+echo "========================================================================="
+echo
+echo "    Make sure you have review the source difference beforce pushing!"
+echo "    Press Control+C once you want to abort this script"
+echo
+echo "========================================================================="
+echo
+
+echo "[0/4] Press any key to start"
+read -s -n 1
+echo "[1/4] Regenerating sources files"
+regenerate_source
+echo "[1/4] Regenerating sources files"
+
+echo "[2/4] Press any key to view diff"
+read -s -n 1
+git_diff
+
+echo "[3/4] Press any key to push source to transifix"
+read -s -n 1
+push_source
+
+echo "[4/4] Press any key to pull translations"
+read -s -n 1
+pull_translations
+echo "[4/4] All Done"
diff --git a/seafile-applet.rc.in b/seafile-applet.rc.in
new file mode 100644 (file)
index 0000000..93cd477
--- /dev/null
@@ -0,0 +1,40 @@
+#include <winver.h>
+#define RC_VERSION ${SEAFILE_CLIENT_VERSION_MAJOR}, ${SEAFILE_CLIENT_VERSION_MINOR}, ${SEAFILE_CLIENT_VERSION_PATCH}, 0
+#define RC_VERSION_STR "${SEAFILE_CLIENT_VERSION_MAJOR}.${SEAFILE_CLIENT_VERSION_MINOR}.${SEAFILE_CLIENT_VERSION_PATCH}.0\0"
+LANGUAGE  0x09,0x01
+1 24 DISCARDABLE Application.manifest
+2 ICON  DISCARDABLE "seafile.ico"
+VS_VERSION_INFO VERSIONINFO
+  FILEVERSION     RC_VERSION
+  PRODUCTVERSION  RC_VERSION
+  FILEFLAGSMASK   0x3fL
+#ifdef _DEBUG
+  FILEFLAGS 0x1L
+#else
+  FILEFLAGS 0x0L
+#endif
+  FILEOS      VOS__WINDOWS32
+  FILETYPE    VFT_APP
+  FILESUBTYPE 0x0L
+
+BEGIN
+  BLOCK "StringFileInfo"
+  BEGIN
+    BLOCK "040904b0"
+    BEGIN
+      VALUE "CompanyName",         "Seafile Ltd.\0"
+      VALUE "FileDescription",     "Seafile Client"
+      VALUE "FileVersion",         RC_VERSION_STR
+      VALUE "InternalName",        "seafile-applet\0"
+      VALUE "OriginalFilename",    "seafile-applet.exe\0"
+      VALUE "LegalCopyright",      "2015 Seafile Ltd.\0"
+      VALUE "ProductName",         "Seafile Client\0"
+      VALUE "ProductVersion",      RC_VERSION_STR
+    END
+  END
+
+  BLOCK "VarFileInfo"
+  BEGIN
+    VALUE "Translation", 0x409, 1200
+  END
+END
diff --git a/seafile-client.qrc b/seafile-client.qrc
new file mode 100644 (file)
index 0000000..bb26c5b
--- /dev/null
@@ -0,0 +1,259 @@
+<RCC>
+<qresource>
+    <file>images/seafile.png</file>
+    <file>images/seafile-24.png</file>
+    <file>images/seafile-32.png</file>
+    <file>images/account.png</file>
+    <file>images/account@2x.png</file>
+    <file>images/folder.png</file>
+    <file>images/loading-spinner.gif</file>
+    <file>images/daemon_up.png</file>
+    <file>images/daemon_down.png</file>
+    <file>images/seafile_auto_sync_disabled.png</file>
+    <file>images/seafile_transfer_1.png</file>
+    <file>images/seafile_transfer_2.png</file>
+    <file>images/seafile_warning.png</file>
+    <file>images/notification.png</file>
+    <file>images/win/daemon_up.ico</file>
+    <file>images/win/daemon_down.ico</file>
+    <file>images/win/seafile_warning.ico</file>
+    <file>images/win/seafile_auto_sync_disabled.ico</file>
+    <file>images/win/seafile_transfer_1.ico</file>
+    <file>images/win/seafile_transfer_2.ico</file>
+    <file>images/win/notification.ico</file>
+    <file>images/mac/daemon_down.png</file>
+    <file>images/mac/daemon_down@2x.png</file>
+    <file>images/mac/daemon_down_white.png</file>
+    <file>images/mac/daemon_down_white@2x.png</file>
+    <file>images/mac/daemon_up.png</file>
+    <file>images/mac/daemon_up@2x.png</file>
+    <file>images/mac/daemon_up_white.png</file>
+    <file>images/mac/daemon_up_white@2x.png</file>
+    <file>images/mac/notification.png</file>
+    <file>images/mac/notification@2x.png</file>
+    <file>images/mac/notification_white.png</file>
+    <file>images/mac/seafile_auto_sync_disabled.png</file>
+    <file>images/mac/seafile_auto_sync_disabled@2x.png</file>
+    <file>images/mac/seafile_auto_sync_disabled_white.png</file>
+    <file>images/mac/seafile_auto_sync_disabled_white@2x.png</file>
+    <file>images/mac/seafile_transfer_1.png</file>
+    <file>images/mac/seafile_transfer_1_white.png</file>
+    <file>images/mac/seafile_transfer_2.png</file>
+    <file>images/mac/seafile_transfer_2_white.png</file>
+    <file>images/mac/seafile_warning.png</file>
+    <file>images/mac/seafile_warning@2x.png</file>
+    <file>images/mac/seafile_warning_white.png</file>
+    <file>images/mac/seafile_warning_white@2x.png</file>
+    <file>images/resync.png</file>
+    <file>images/resync@2x.png</file>
+    <file>images/minus-gray.png</file>
+    <file>images/minus-gray@2x.png</file>
+    <file>images/info.png</file>
+    <file>images/info-gray.png</file>
+    <file>images/info-gray@2x.png</file>
+    <file>images/play-gray.png</file>
+    <file>images/play-gray@2x.png</file>
+    <file>images/pause-gray.png</file>
+    <file>images/pause-gray@2x.png</file>
+    <file>images/cloud-gray.png</file>
+    <file>images/cloud-gray@2x.png</file>
+    <file>images/leave-share.png</file>
+    <file>images/leave-share@2x.png</file>
+    <file>images/sync_now-gray.png</file>
+    <file>images/sync_now-gray@2x.png</file>
+    <file>images/remove-gray.png</file>
+    <file>images/remove-gray@2x.png</file>
+    <file>images/remove-red.png</file>
+    <file>images/share.png</file>
+    <file>images/share@2x.png</file>
+    <file>images/clock.png</file>
+    <file>images/clock@2x.png</file>
+    <file>images/main-panel/folder.png</file>
+    <file>images/main-panel/folder@2x.png</file>
+    <file>images/main-panel/search-background.png</file>
+    <file>images/main-panel/search-background@2x.png</file>
+    <file>images/main-panel/library-normal.png</file>
+    <file>images/main-panel/library-normal@2x.png</file>
+    <file>images/main-panel/library-encrypted.png</file>
+    <file>images/main-panel/library-encrypted@2x.png</file>
+    <file>images/main-panel/library-readonly.png</file>
+    <file>images/main-panel/library-readonly@2x.png</file>
+    <file>images/main-panel/network-error.png</file>
+    <file>images/main-panel/network-error@2x.png</file>
+    <file>images/main-panel/upload.png</file>
+    <file>images/main-panel/upload@2x.png</file>
+    <file>images/main-panel/download.png</file>
+    <file>images/main-panel/download@2x.png</file>
+    <file>images/sync/done.png</file>
+    <file>images/sync/done@2x.png</file>
+    <file>images/sync/cloud-sync.png</file>
+    <file>images/sync/cloud-sync@2x.png</file>
+    <file>images/sync/cloud-synced.png</file>
+    <file>images/sync/cloud-synced@2x.png</file>
+    <file>images/sync/cloud-unsynced.png</file>
+    <file>images/sync/cloud-unsynced@2x.png</file>
+    <file>images/sync/exclamation.png</file>
+    <file>images/sync/minus-sign.png</file>
+    <file>images/sync/pause.png</file>
+    <file>images/sync/pause@2x.png</file>
+    <file>images/sync/question.png</file>
+    <file>images/sync/status-done.png</file>
+    <file>images/sync/status-done@2x.png</file>
+    <file>images/sync/status-syncing.png</file>
+    <file>images/sync/status-syncing@2x.png</file>
+    <file>images/sync/waiting.png</file>
+    <file>images/sync/waiting@2x.png</file>
+    <file>images/download-48.png</file>
+    <file>images/tabs/star-normal.png</file>
+    <file>images/tabs/star-normal@2x.png</file>
+    <file>images/tabs/history-normal.png</file>
+    <file>images/tabs/history-normal@2x.png</file>
+    <file>images/tabs/search-normal.png</file>
+    <file>images/tabs/search-normal@2x.png</file>
+    <file>images/tabs/library-normal.png</file>
+    <file>images/tabs/library-normal@2x.png</file>
+    <file>images/tabs/highlighted/star-orange.png</file>
+    <file>images/tabs/highlighted/star-orange@2x.png</file>
+    <file>images/tabs/highlighted/library-orange.png</file>
+    <file>images/tabs/highlighted/library-orange@2x.png</file>
+    <file>images/tabs/highlighted/search-orange.png</file>
+    <file>images/tabs/highlighted/search-orange@2x.png</file>
+    <file>images/tabs/highlighted/history-orange.png</file>
+    <file>images/tabs/highlighted/history-orange@2x.png</file>
+    <file>images/files/file_audio.png</file>
+    <file>images/library-256.png</file>
+    <file>images/files/file_audio@2x.png</file>
+    <file>images/files/file_folder.png</file>
+    <file>images/files/file_folder@2x.png</file>
+    <file>images/files/file_folder_readonly.png</file>
+    <file>images/files/file_folder_readonly@2x.png</file>
+    <file>images/files/file_image.png</file>
+    <file>images/files/file_image@2x.png</file>
+    <file>images/files/file_ms_excel.png</file>
+    <file>images/files/file_ms_excel@2x.png</file>
+    <file>images/files/file_ms_ppt.png</file>
+    <file>images/files/file_ms_ppt@2x.png</file>
+    <file>images/files/file_ms_word.png</file>
+    <file>images/files/file_ms_word@2x.png</file>
+    <file>images/files/file_pdf.png</file>
+    <file>images/files/file_pdf@2x.png</file>
+    <file>images/files/file_text.png</file>
+    <file>images/files/file_text@2x.png</file>
+    <file>images/files/file_unknown.png</file>
+    <file>images/files/file_unknown@2x.png</file>
+    <file>images/files/file_video.png</file>
+    <file>images/files/file_video@2x.png</file>
+    <file>images/files/file_zip.png</file>
+    <file>images/files/file_zip@2x.png</file>
+    <file>images/files_v2/file_audio.png</file>
+    <file>images/files_v2/file_audio@2x.png</file>
+    <file>images/files_v2/file_folder_readonly.png</file>
+    <file>images/files_v2/file_folder_readonly@2x.png</file>
+    <file>images/files_v2/file_folder.png</file>
+    <file>images/files_v2/file_folder@2x.png</file>
+    <file>images/files_v2/file_image.png</file>
+    <file>images/files_v2/file_image@2x.png</file>
+    <file>images/files_v2/file_ms_excel.png</file>
+    <file>images/files_v2/file_ms_excel@2x.png</file>
+    <file>images/files_v2/file_ms_ppt.png</file>
+    <file>images/files_v2/file_ms_ppt@2x.png</file>
+    <file>images/files_v2/file_ms_word.png</file>
+    <file>images/files_v2/file_ms_word@2x.png</file>
+    <file>images/files_v2/file_pdf.png</file>
+    <file>images/files_v2/file_pdf@2x.png</file>
+    <file>images/files_v2/file_text.png</file>
+    <file>images/files_v2/file_text@2x.png</file>
+    <file>images/files_v2/file_video.png</file>
+    <file>images/files_v2/file_video@2x.png</file>
+    <file>images/files_v2/file_zip.png</file>
+    <file>images/files_v2/file_zip@2x.png</file>
+    <file>images/files_v2/file_unknown.png</file>
+    <file>images/files_v2/file_unknown@2x.png</file>
+    <file>images/account-settings.png</file>
+    <file>images/account-settings@2x.png</file>
+    <file>images/add-account.png</file>
+    <file>images/add-account@2x.png</file>
+    <file>images/delete-account.png</file>
+    <file>images/delete-account@2x.png</file>
+    <file>images/account-checked.png</file>
+    <file>images/account-checked@2x.png</file>
+    <file>images/account-else.png</file>
+    <file>images/account-else@2x.png</file>
+    <file>images/logout.png</file>
+    <file>images/logout@2x.png</file>
+    <file>images/cancel.png</file>
+    <file>images/cancel@2x.png</file>
+    <file>images/filebrowser/backward.png</file>
+    <file>images/filebrowser/backward@2x.png</file>
+    <file>images/filebrowser/forward.png</file>
+    <file>images/filebrowser/forward@2x.png</file>
+    <file>images/filebrowser/home.png</file>
+    <file>images/filebrowser/home@2x.png</file>
+    <file>images/filebrowser/path-separator.png</file>
+    <file>images/filebrowser/path-separator@2x.png</file>
+    <file>images/filebrowser/settings.png</file>
+    <file>images/filebrowser/settings@2x.png</file>
+    <file>images/filebrowser/up-arrow.png</file>
+    <file>images/filebrowser/down-arrow.png</file>
+    <file>images/filebrowser/locked.png</file>
+    <file>images/filebrowser/locked@2x.png</file>
+    <file>images/filebrowser/locked-by-me.png</file>
+    <file>images/filebrowser/locked-by-me@2x.png</file>
+    <file>images/filebrowser/refresh-gray.png</file>
+    <file>images/filebrowser/refresh-gray@2x.png</file>
+    <file>images/filebrowser/add.png</file>
+    <file>images/filebrowser/add@2x.png</file>
+    <file>images/toolbar/add.png</file>
+    <file>images/toolbar/add@2x.png</file>
+    <file>images/toolbar/add-gray.png</file>
+    <file>images/toolbar/add-gray@2x.png</file>
+    <file>images/toolbar/download.png</file>
+    <file>images/toolbar/download@2x.png</file>
+    <file>images/toolbar/download-gray.png</file>
+    <file>images/toolbar/download-gray@2x.png</file>
+    <file>images/toolbar/file.png</file>
+    <file>images/toolbar/file@2x.png</file>
+    <file>images/toolbar/file-gray.png</file>
+    <file>images/toolbar/file-gray@2x.png</file>
+    <file>images/toolbar/refresh-gray.png</file>
+    <file>images/toolbar/refresh-gray@2x.png</file>
+    <file>images/toolbar/refresh.png</file>
+    <file>images/toolbar/refresh@2x.png</file>
+    <file>images/toolbar/refresh-new.png</file>
+    <file>images/toolbar/refresh-new@2x.png</file>
+    <file>images/toolbar/refresh-orange.png</file>
+    <file>images/toolbar/refresh-orange@2x.png</file>
+    <file>qt.css</file>
+    <file>qt-win.css</file>
+    <file>qt-mac.css</file>
+    <file>i18n/seafile_ca.qm</file>
+    <file>i18n/seafile_de_DE.qm</file>
+    <file>i18n/seafile_en.qm</file>
+    <file>i18n/seafile_es.qm</file>
+    <file>i18n/seafile_es_AR.qm</file>
+    <file>i18n/seafile_es_MX.qm</file>
+    <file>i18n/seafile_fr_FR.qm</file>
+    <file>i18n/seafile_he_IL.qm</file>
+    <file>i18n/seafile_hu_HU.qm</file>
+    <file>i18n/seafile_is.qm</file>
+    <file>i18n/seafile_it.qm</file>
+    <file>i18n/seafile_ko_KR.qm</file>
+    <file>i18n/seafile_nl_BE.qm</file>
+    <file>i18n/seafile_pl_PL.qm</file>
+    <file>i18n/seafile_pt_BR.qm</file>
+    <file>i18n/seafile_pt_PT.qm</file>
+    <file>i18n/seafile_ru.qm</file>
+    <file>i18n/seafile_sk_SK.qm</file>
+    <file>i18n/seafile_uk.qm</file>
+    <file>i18n/seafile_zh_CN.qm</file>
+    <file>i18n/seafile_zh_TW.qm</file>
+    <file>i18n/seafile_tr.qm</file>
+    <file>i18n/seafile_nl_NL.qm</file>
+    <file>i18n/seafile_lv.qm</file>
+    <file>i18n/seafile_ja.qm</file>
+    <file>i18n/seafile_sv.qm</file>
+    <file>i18n/seafile_cs_CZ.qm</file>
+    <file>i18n/seafile_el_GR.qm</file>
+    <file>i18n/seafile_nb_NO.qm</file>
+</qresource>
+</RCC>
diff --git a/seafile.icns b/seafile.icns
new file mode 100644 (file)
index 0000000..4a4d90c
Binary files /dev/null and b/seafile.icns differ
diff --git a/seafile.ico b/seafile.ico
new file mode 100644 (file)
index 0000000..dba33e6
Binary files /dev/null and b/seafile.ico differ
diff --git a/sparkle-readme.md b/sparkle-readme.md
new file mode 100644 (file)
index 0000000..26ca254
--- /dev/null
@@ -0,0 +1,39 @@
+## Setup WinSparkle environment
+
+[WinSparkle](https://github.com/vslavik/winsparkle) 是 Mac 上的 Sparkle 框架在 windows 上的实现,用于软件自动更新.
+
+* 下载 winsparkle 发布包  https://github.com/vslavik/winsparkle/releases/download/v0.5.3/WinSparkle-0.5.3.zip, 并解压
+* 把 include 下的文件拷贝到 /usr/local/lib
+* 把 Release/winsparkle.dll 拷贝到 /mingw32/bin
+* 把 winsparkle.lib 拷贝到 seafile-client 目录下
+
+在编译时需要加上 `BUILD_SPARKLE_SUPPORT` flag:
+```sh
+cmake -DBUILD_SPARKLE_SUPPORT=ON .
+```
+
+
+## 更新 appcast.xml
+
+winsparkle 根据下载下来的 appcast.xml 中的数据:
+
+- 判断当前是否有更新版本
+- 新版本的下载地址
+- 新版本的 release notes (展示给用户看)
+
+发布新的版本时,需要更新appcast中的哪些字段:
+
+- pubDate 字段
+- enclosure 中新版本的下载地址 url 字段
+- enclosure 中新版本的版本号 sparkle:version 字段
+
+### 本地开发时如何搭建一个简单的 server 来让 seafile-client 去获取 appcast.xml
+
+- 将 appcast.example.xml 修改一下
+- 然后本地启动一个 nginx 服务器
+- 设置 `SEAFILE_CLIENT_APPCAST_URI` 环境变量, 然后启动 seafile-applet.
+
+```sh
+export SEAFILE_CLIENT_APPCAST_URI=http://localhost:8888/appcast.xml
+./seafile-applet.exe
+```
diff --git a/src/account-info-service.cpp b/src/account-info-service.cpp
new file mode 100644 (file)
index 0000000..2f198b4
--- /dev/null
@@ -0,0 +1,64 @@
+#include <QTimer>
+
+#include "account-info-service.h"
+#include "account-mgr.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "seafile-applet.h"
+
+namespace
+{
+// const int kRefreshInterval = 3 * 60 * 1000; // 3 min
+}
+
+SINGLETON_IMPL(AccountInfoService)
+
+AccountInfoService::AccountInfoService(QObject* parent)
+    : QObject(parent), request_(NULL)
+{
+    refresh_timer_ = new QTimer(this);
+    connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refresh()));
+    refresh();
+}
+
+void AccountInfoService::start()
+{
+    // refresh_timer_->start(kRefreshInterval);
+}
+
+void AccountInfoService::stop()
+{
+    refresh_timer_->stop();
+}
+
+void AccountInfoService::refresh()
+{
+    const Account account = seafApplet->accountManager()->currentAccount();
+    if (!account.isValid()) {
+        return;
+    }
+    if (request_) {
+        request_->deleteLater();
+    }
+
+    request_ = new FetchAccountInfoRequest(account);
+    connect(request_, SIGNAL(success(const AccountInfo&)), this,
+            SLOT(onFetchAccountInfoSuccess(const AccountInfo&)));
+    connect(request_, SIGNAL(failed(const ApiError&)), this,
+            SLOT(onFetchAccountInfoFailed()));
+    request_->send();
+}
+
+
+void AccountInfoService::onFetchAccountInfoSuccess(const AccountInfo& info)
+{
+    seafApplet->accountManager()->updateAccountInfo(request_->account(), info);
+    request_->deleteLater();
+    request_ = NULL;
+}
+
+void AccountInfoService::onFetchAccountInfoFailed()
+{
+    request_->deleteLater();
+    request_ = NULL;
+}
diff --git a/src/account-info-service.h b/src/account-info-service.h
new file mode 100644 (file)
index 0000000..1b42a89
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef SEAFILE_CLIENT_ACCOUNT_INFO_SERVICE_H
+#define SEAFILE_CLIENT_ACCOUNT_INFO_SERVICE_H
+
+#include <QObject>
+#include <QList>
+#include <QUrl>
+#include <QHash>
+
+#include "utils/singleton.h"
+
+class QTimer;
+
+class FetchAccountInfoRequest;
+class ApiError;
+class AccountInfo;
+
+
+class AccountInfoService : public QObject
+{
+    Q_OBJECT
+    SINGLETON_DEFINE(AccountInfoService)
+
+public:
+    void start();
+    void stop();
+
+public slots:               
+    void refresh();
+
+private slots:
+    void onFetchAccountInfoSuccess(const AccountInfo& info);
+    void onFetchAccountInfoFailed();
+
+private:
+    Q_DISABLE_COPY(AccountInfoService)
+    AccountInfoService(QObject *parent=0);
+
+    QTimer *refresh_timer_;
+    FetchAccountInfoRequest *request_;
+};
+
+
+#endif // SEAFILE_CLIENT_ACCOUNT_INFO_SERVICE_H
diff --git a/src/account-mgr.cpp b/src/account-mgr.cpp
new file mode 100644 (file)
index 0000000..b940467
--- /dev/null
@@ -0,0 +1,806 @@
+#include <sqlite3.h>
+#include <glib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <algorithm>
+
+#include <QDateTime>
+#include <QMutexLocker>
+
+#include "account-mgr.h"
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "utils/utils.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "account-info-service.h"
+#include "ui/login-dialog.h"
+#include "shib/shib-login-dialog.h"
+#include "settings-mgr.h"
+
+namespace {
+const char *kRepoRelayAddrProperty = "relay-address";
+const char *kVersionKeyName = "version";
+const char *kFeaturesKeyName = "features";
+const char *kEncryptedLibraryVersionName = "encrypted_library_version";
+const char *kCustomBrandKeyName = "custom-brand";
+const char *kCustomLogoKeyName = "custom-logo";
+const char *kTotalStorage = "storage.total";
+const char *kUsedStorage = "storage.used";
+const char *kNickname = "name";
+
+struct ColumnCheckData {
+    QString name;
+    bool exists;
+};
+
+bool getColumnInfoCallback(sqlite3_stmt *stmt, void *data)
+{
+    ColumnCheckData *cdata = (ColumnCheckData *)data;
+    const char *column_name = (const char *)sqlite3_column_text (stmt, 1);
+
+    if (cdata->name == QString(column_name)) {
+        cdata->exists = true;
+        return false;
+    }
+
+    return true;
+}
+
+void addNewColumnToAccountsTable(struct sqlite3* db, const QString& name, const QString& type)
+{
+    QString sql = "PRAGMA table_info(Accounts);";
+    ColumnCheckData cdata;
+    cdata.name = name;
+    cdata.exists = false;
+    sqlite_foreach_selected_row (db, toCStr(sql), getColumnInfoCallback, &cdata);
+    if (!cdata.exists) {
+        sql = QString("ALTER TABLE Accounts ADD COLUMN %1 %2").arg(name).arg(type);
+        if (sqlite_query_exec (db, toCStr(sql)) < 0) {
+            qCritical("unable to create column %s\n", toCStr(name));
+        }
+    }
+}
+
+bool compareAccount(const Account& a, const Account& b)
+{
+    if (!a.isValid()) {
+        return false;
+    } else if (!b.isValid()) {
+        return true;
+    } else if (a.lastVisited < b.lastVisited) {
+        return false;
+    } else if (a.lastVisited > b.lastVisited) {
+        return true;
+    }
+
+    return true;
+}
+
+struct UserData {
+    std::vector<Account> *accounts;
+    struct sqlite3 *db;
+};
+
+inline void setServerInfoKeyValue(struct sqlite3 *db, const Account &account, const QString& key, const QString &value)
+{
+    char *zql = sqlite3_mprintf(
+        "REPLACE INTO ServerInfo(url, username, key, value) VALUES (%Q, %Q, %Q, %Q)",
+        account.serverUrl.toEncoded().data(), account.username.toUtf8().data(),
+        key.toUtf8().data(), value.toUtf8().data());
+    sqlite_query_exec(db, zql);
+    sqlite3_free(zql);
+}
+
+QStringList collectSyncedReposForAccount(const Account& account)
+{
+    std::vector<LocalRepo> repos;
+    SeafileRpcClient *rpc = seafApplet->rpcClient();
+    rpc->listLocalRepos(&repos);
+    QStringList repo_ids;
+    for (size_t i = 0; i < repos.size(); i++) {
+        LocalRepo repo = repos[i];
+        QString repo_server_url;
+        if (rpc->getRepoProperty(repo.id, "server-url", &repo_server_url) < 0) {
+            continue;
+        }
+        if (QUrl(repo_server_url).host() != account.serverUrl.host()) {
+            continue;
+        }
+        QString token;
+        if (rpc->getRepoProperty(repo.id, "token", &token) < 0 || token.isEmpty()) {
+            repo_ids.append(repo.id);
+        }
+    }
+
+    return repo_ids;
+}
+
+}
+
+AccountManager::AccountManager()
+{
+    db = NULL;
+}
+
+AccountManager::~AccountManager()
+{
+    if (db)
+        sqlite3_close(db);
+}
+
+int AccountManager::start()
+{
+    const char *errmsg;
+    const char *sql;
+
+    QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("accounts.db");
+    if (sqlite3_open (toCStr(db_path), &db)) {
+        errmsg = sqlite3_errmsg (db);
+        qCritical("failed to open account database %s: %s",
+                toCStr(db_path), errmsg ? errmsg : "no error given");
+
+        seafApplet->errorAndExit(tr("failed to open account database"));
+        return -1;
+    }
+
+    // enabling foreign keys, it must be done manually from each connection
+    // and this feature is only supported from sqlite 3.6.19
+    sql = "PRAGMA foreign_keys=ON;";
+    if (sqlite_query_exec (db, sql) < 0) {
+        qCritical("sqlite version is too low to support foreign key feature\n");
+        sqlite3_close(db);
+        db = NULL;
+        return -1;
+    }
+
+    sql = "CREATE TABLE IF NOT EXISTS Accounts (url VARCHAR(24), "
+        "username VARCHAR(15), token VARCHAR(40), lastVisited INTEGER, "
+        "PRIMARY KEY(url, username))";
+    if (sqlite_query_exec (db, sql) < 0) {
+        qCritical("failed to create accounts table\n");
+        sqlite3_close(db);
+        db = NULL;
+        return -1;
+    }
+
+    addNewColumnToAccountsTable(db, "isShibboleth", "INTEGER");
+    addNewColumnToAccountsTable(db, "AutomaticLogin", "INTEGER default 1");
+    addNewColumnToAccountsTable(db, "s2fa_token", "TEXT");
+
+    // ServerInfo table is used to store any (key, value) information for an
+    // account.
+    sql = "CREATE TABLE IF NOT EXISTS ServerInfo ("
+        "key TEXT NOT NULL, value TEXT, "
+        "url VARCHAR(24), username VARCHAR(15), "
+        "PRIMARY KEY(url, username, key), "
+        "FOREIGN KEY(url, username) REFERENCES Accounts(url, username) "
+        "ON DELETE CASCADE ON UPDATE CASCADE )";
+    if (sqlite_query_exec (db, sql) < 0) {
+        qCritical("failed to create server_info table\n");
+        sqlite3_close(db);
+        db = NULL;
+        return -1;
+    }
+
+    loadAccounts();
+
+    connect(this, SIGNAL(accountsChanged()), this, SLOT(onAccountsChanged()));
+    connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(onAboutToQuit()));
+    connect(this, SIGNAL(accountRequireRelogin(const Account&)),
+            this, SLOT(reloginAccount(const Account &)));
+    return 0;
+}
+
+void AccountManager::onAboutToQuit()
+{
+    logoutDeviceNonautoLogin();
+}
+
+bool AccountManager::loadAccountsCB(sqlite3_stmt *stmt, void *data)
+{
+    UserData *userdata = static_cast<UserData*>(data);
+    const char *url = (const char *)sqlite3_column_text (stmt, 0);
+    const char *username = (const char *)sqlite3_column_text (stmt, 1);
+    const char *token = (const char *)sqlite3_column_text (stmt, 2);
+    qint64 atime = (qint64)sqlite3_column_int64 (stmt, 3);
+    int isShibboleth = sqlite3_column_int (stmt, 4);
+    int isAutomaticLogin = sqlite3_column_int (stmt, 5);
+    const char *s2fa_token = (const char *)sqlite3_column_text (stmt,6);
+
+    if (!token) {
+        token = "";
+    }
+
+    if (!s2fa_token) {
+        s2fa_token = "";
+    }
+
+    Account account = Account(QUrl(QString(url)), QString(username),
+                              QString(token), atime, isShibboleth != 0,
+                              isAutomaticLogin != 0, QString(s2fa_token));
+    char* zql = sqlite3_mprintf("SELECT key, value FROM ServerInfo WHERE url = %Q AND username = %Q", url, username);
+    sqlite_foreach_selected_row (userdata->db, zql, loadServerInfoCB, &account);
+    sqlite3_free(zql);
+
+    userdata->accounts->push_back(account);
+    return true;
+}
+
+bool AccountManager::loadServerInfoCB(sqlite3_stmt *stmt, void *data)
+{
+    Account *account = static_cast<Account*>(data);
+    const char *key = (const char *)sqlite3_column_text (stmt, 0);
+    const char *value = (const char *)sqlite3_column_text (stmt, 1);
+    QString key_string = key;
+    QString value_string = value;
+    if (key_string == kVersionKeyName) {
+        account->serverInfo.parseVersionFromString(value_string);
+    } else if (key_string == kEncryptedLibraryVersionName) {
+        account->serverInfo.parseEncryptedLibraryVersionFromString(value_string);
+    } else if (key_string == kFeaturesKeyName) {
+        account->serverInfo.parseFeatureFromStrings(value_string.split(","));
+    } else if (key_string == kCustomBrandKeyName) {
+        account->serverInfo.customBrand = value_string;
+    } else if (key_string == kCustomLogoKeyName) {
+        account->serverInfo.customLogo = value_string;
+    } else if (key_string == kTotalStorage) {
+        account->accountInfo.totalStorage = value_string.toLongLong();
+    } else if (key_string == kUsedStorage) {
+        account->accountInfo.usedStorage = value_string.toLongLong();
+    } else if (key_string == kNickname) {
+        account->accountInfo.name = value_string;
+    }
+    return true;
+}
+
+const std::vector<Account>& AccountManager::loadAccounts()
+{
+    const char *sql = "SELECT url, username, token, lastVisited, isShibboleth, AutomaticLogin, s2fa_token "
+                      "FROM Accounts ORDER BY lastVisited DESC";
+    accounts_.clear();
+    UserData userdata;
+    userdata.accounts = &accounts_;
+    userdata.db = db;
+    sqlite_foreach_selected_row (db, sql, loadAccountsCB, &userdata);
+
+    std::stable_sort(accounts_.begin(), accounts_.end(), compareAccount);
+    return accounts_;
+}
+
+int AccountManager::saveAccount(const Account& account)
+{
+    Account new_account = account;
+    bool account_exist = false;
+    {
+        QMutexLocker lock(&accounts_mutex_);
+        for (size_t i = 0; i < accounts_.size(); i++) {
+            if (accounts_[i] == account) {
+                accounts_.erase(accounts_.begin() + i);
+                account_exist = true;
+                break;
+            }
+        }
+        accounts_.insert(accounts_.begin(), new_account);
+    }
+    updateServerInfo(0);
+
+    qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
+
+    char *zql;
+    if (account_exist) {
+        zql = sqlite3_mprintf(
+            "UPDATE Accounts SET token = %Q, lastVisited = %Q, isShibboleth = %Q, AutomaticLogin = %Q, s2fa_token = %Q"
+            "WHERE url = %Q AND username = %Q",
+            // token
+            new_account.token.toUtf8().data(),
+            // lastVisited
+            QString::number(timestamp).toUtf8().data(),
+            // isShibboleth
+            QString::number(new_account.isShibboleth).toUtf8().data(),
+            // isAutomaticLogin
+            QString::number(new_account.isAutomaticLogin).toUtf8().data(),
+            //s2fa_token
+            new_account.s2fa_token.toUtf8().data(),
+            // url
+            new_account.serverUrl.toEncoded().data(),
+            // username
+            new_account.username.toUtf8().data());
+    } else {
+        zql = sqlite3_mprintf(
+            "INSERT INTO Accounts(url, username, token, lastVisited, isShibboleth, AutomaticLogin, s2fa_token) "
+            "VALUES (%Q, %Q, %Q, %Q, %Q, %Q, %Q) ",
+            // url
+            new_account.serverUrl.toEncoded().data(),
+            // username
+            new_account.username.toUtf8().data(),
+            // token
+            new_account.token.toUtf8().data(),
+            // lastVisited
+            QString::number(timestamp).toUtf8().data(),
+            // isShibboleth
+            QString::number(new_account.isShibboleth).toUtf8().data(),
+            // isAutomaticLogin
+            QString::number(new_account.isAutomaticLogin).toUtf8().data(),
+            //s2fa_token
+            new_account.s2fa_token.toUtf8().data());
+    }
+    sqlite_query_exec(db, zql);
+    sqlite3_free(zql);
+
+    emit accountsChanged();
+
+    return 0;
+}
+
+int AccountManager::removeAccount(const Account& account)
+{
+    char *zql = sqlite3_mprintf(
+        "DELETE FROM Accounts WHERE url = %Q AND username = %Q",
+        // url
+        account.serverUrl.toEncoded().data(),
+        // username
+        account.username.toUtf8().data());
+    sqlite_query_exec(db, zql);
+    sqlite3_free(zql);
+
+    bool need_switch_account = currentAccount() == account;
+
+    {
+        QMutexLocker lock(&accounts_mutex_);
+        accounts_.erase(
+            std::remove(accounts_.begin(), accounts_.end(), account),
+            accounts_.end());
+    }
+
+    if (need_switch_account) {
+        if (!accounts_.empty()) {
+            validateAndUseAccount(accounts_[0]);
+        } else {
+            LoginDialog login_dialog;
+            login_dialog.exec();
+        }
+    }
+
+    emit accountsChanged();
+
+    return 0;
+}
+
+void AccountManager::logoutDevice(const Account& account)
+{
+    clearSyncToken(account);
+    clearAccountToken(account);
+}
+
+void AccountManager::logoutDeviceNonautoLogin()
+{
+    QMutexLocker lock(&accounts_mutex_);
+    for (const Account& account : accounts_) {
+        if (account.isAutomaticLogin) {
+            continue;
+        }
+        clearSyncToken(account);
+        clearAccountToken(account);
+    }
+}
+
+void AccountManager::updateAccountLastVisited(const Account& account)
+{
+    char *zql = sqlite3_mprintf(
+        "UPDATE Accounts SET lastVisited = %Q "
+        "WHERE url = %Q AND username = %Q",
+        // lastVisted
+        QString::number(QDateTime::currentMSecsSinceEpoch()).toUtf8().data(),
+        // url
+        account.serverUrl.toEncoded().data(),
+        // username
+        account.username.toUtf8().data());
+    sqlite_query_exec(db, zql);
+    sqlite3_free(zql);
+}
+
+bool AccountManager::accountExists(const QUrl& url, const QString& username)
+{
+    for (size_t i = 0; i < accounts_.size(); i++) {
+        if (accounts_[i].serverUrl == url && accounts_[i].username == username) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool AccountManager::validateAndUseAccount(const Account& account)
+{
+    if (!account.isAutomaticLogin) {
+        clearAccountToken(account);
+        return reloginAccount(account);
+    }
+    else if (!account.isValid()) {
+        return reloginAccount(account);
+    }
+    else {
+        return setCurrentAccount(account);
+    }
+}
+
+bool AccountManager::setCurrentAccount(const Account& account)
+{
+    Q_ASSERT(account.isValid());
+
+    if (account == currentAccount()) {
+        return false;
+    }
+
+    emit beforeAccountSwitched();
+
+    // Would emit "accountsChanged" signal
+    saveAccount(account);
+
+    AccountInfoService::instance()->refresh();
+
+    return true;
+}
+
+int AccountManager::replaceAccount(const Account& old_account, const Account& new_account)
+{
+    {
+        QMutexLocker lock(&accounts_mutex_);
+        for (size_t i = 0; i < accounts_.size(); i++) {
+            if (accounts_[i] == old_account) {
+                // TODO copy new_account and old_account before this operation
+                // we might have invalid old_account or new_account after it
+                accounts_[i] = new_account;
+                updateServerInfo(i);
+                break;
+            }
+        }
+    }
+
+    qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
+
+    char *zql = sqlite3_mprintf(
+        "UPDATE Accounts "
+        "SET url = %Q, "
+        "    username = %Q, "
+        "    token = %Q, "
+        "    lastVisited = %Q, "
+        "    isShibboleth = %Q, "
+        "    AutomaticLogin = %Q "
+        "WHERE url = %Q "
+        "  AND username = %Q",
+        // new_url
+        new_account.serverUrl.toEncoded().data(),
+        // username
+        new_account.username.toUtf8().data(),
+        // token
+        new_account.token.toUtf8().data(),
+        // lastvisited
+        QString::number(timestamp).toUtf8().data(),
+        // isShibboleth
+        QString::number(new_account.isShibboleth).toUtf8().data(),
+        // isAutomaticLogin
+        QString::number(new_account.isAutomaticLogin).toUtf8().data(),
+        // old_url
+        old_account.serverUrl.toEncoded().data(),
+        // username
+        new_account.username.toUtf8().data()
+        );
+
+    sqlite_query_exec(db, zql);
+    sqlite3_free(zql);
+
+    emit accountsChanged();
+
+    return 0;
+}
+
+Account AccountManager::getAccountByHostAndUsername(const QString& host,
+                                                    const QString& username) const
+{
+    for (size_t i = 0; i < accounts_.size(); i++) {
+        if (accounts_[i].serverUrl.host() == host
+            && accounts_[i].username == username) {
+            return accounts_[i];
+        }
+    }
+
+    return Account();
+}
+
+Account AccountManager::getAccountBySignature(const QString& account_sig) const
+{
+    for (size_t i = 0; i < accounts_.size(); i++) {
+        if (accounts_[i].getSignature() == account_sig) {
+            return accounts_[i];
+        }
+    }
+
+    return Account();
+}
+
+void AccountManager::updateServerInfo()
+{
+    for (size_t i = 0; i < accounts_.size(); i++)
+        updateServerInfo(i);
+}
+
+void AccountManager::updateServerInfo(unsigned index)
+{
+    ServerInfoRequest *request;
+    // request is taken owner by Account object
+    request = accounts_[index].createServerInfoRequest();
+    connect(request, SIGNAL(success(const Account&, const ServerInfo &)),
+            this, SLOT(serverInfoSuccess(const Account&, const ServerInfo &)));
+    connect(request, SIGNAL(failed(const ApiError&)),
+            this, SLOT(serverInfoFailed(const ApiError&)));
+    request->send();
+}
+
+void AccountManager::updateAccountInfo(const Account& account,
+                                       const AccountInfo& info)
+{
+    setServerInfoKeyValue(db, account, kTotalStorage,
+                          QString::number(info.totalStorage));
+    setServerInfoKeyValue(db, account, kUsedStorage,
+                          QString::number(info.usedStorage));
+    setServerInfoKeyValue(db, account, kNickname,
+                          info.name);
+
+    for (size_t i = 0; i < accounts_.size(); i++) {
+        if (accounts_[i] == account) {
+            accounts_[i].accountInfo = info;
+            emit accountInfoUpdated(accounts_[i]);
+            break;
+        }
+    }
+}
+
+
+void AccountManager::serverInfoSuccess(const Account &_account, const ServerInfo &info)
+{
+    Account account = _account;
+    account.serverInfo = info;
+
+    setServerInfoKeyValue(db, account, kVersionKeyName, info.getVersionString());
+    setServerInfoKeyValue(db, account, kEncryptedLibraryVersionName, QString::number(info.getEncryptedLibraryVersion()));
+    setServerInfoKeyValue(db, account, kFeaturesKeyName, info.getFeatureStrings().join(","));
+    setServerInfoKeyValue(db, account, kCustomLogoKeyName, info.customLogo);
+    setServerInfoKeyValue(db, account, kCustomBrandKeyName, info.customBrand);
+
+    bool changed = _account.serverInfo != info;
+    if (!changed)
+        return;
+
+    QUrl url(account.serverUrl);
+    url.setPath("/");
+    seafApplet->rpcClient()->setServerProperty(
+        url.toString(), "is_pro", account.isPro() ? "true" : "false");
+
+    for (size_t i = 0; i < accounts_.size(); i++) {
+        if (accounts_[i] == account) {
+            if (i == 0)
+                emit beforeAccountSwitched();
+            accounts_[i].serverInfo = info;
+            if (i == 0)
+                emit accountsChanged();
+            break;
+        }
+    }
+}
+
+void AccountManager::serverInfoFailed(const ApiError &error)
+{
+    qWarning("update server info failed %s\n", error.toString().toUtf8().data());
+}
+
+bool AccountManager::clearAccountToken(const Account& account)
+{
+    for (size_t i = 0; i < accounts_.size(); i++) {
+        if (accounts_[i] == account) {
+            accounts_[i].token = "";
+            break;
+        }
+    }
+
+    char *zql = sqlite3_mprintf(
+        "UPDATE Accounts "
+        "SET token = NULL "
+        "WHERE url = %Q "
+        "  AND username = %Q",
+        // url
+        account.serverUrl.toEncoded().data(),
+        // username
+        account.username.toUtf8().data()
+        );
+    sqlite_query_exec(db, zql);
+    sqlite3_free(zql);
+
+    emit accountsChanged();
+
+    return true;
+}
+
+bool AccountManager::clearSyncToken(const Account& account)
+{
+    QString error;
+    if (seafApplet->rpcClient()->removeSyncTokensByAccount(account.serverUrl.host(),
+                                                           account.username,
+                                                           &error)  < 0) {
+        seafApplet->warningBox(
+            tr("Failed to remove local repos sync token: %1").arg(error));
+        return false;
+    } else {
+        return true;
+    }
+}
+
+void AccountManager::removeNonautoLoginSyncTokens()
+{
+    QMutexLocker lock(&accounts_mutex_);
+    for (const Account& account : accounts_) {
+        if (account.isAutomaticLogin) {
+            continue;
+        }
+
+        clearSyncToken(account);
+    }
+    return;
+}
+
+Account AccountManager::getAccountByRepo(const QString& repo_id, SeafileRpcClient *rpc)
+{
+    std::vector<Account> accounts;
+    {
+        QMutexLocker lock(&accounts_mutex_);
+        accounts = accounts_;
+    }
+
+    QMutexLocker cache_lock(&accounts_cache_mutex_);
+
+    if (!accounts_cache_.contains(repo_id)) {
+        QString relay_addr;
+        if (rpc->getRepoProperty(repo_id, kRepoRelayAddrProperty, &relay_addr) < 0) {
+            return Account();
+        }
+
+        for (size_t i = 0; i < accounts.size(); i++) {
+            const Account& account = accounts[i];
+            if (account.serverUrl.host() == relay_addr) {
+                accounts_cache_[repo_id] = account;
+                break;
+            }
+        }
+    }
+    return accounts_cache_.value(repo_id, Account());
+}
+
+Account AccountManager::getAccountByRepo(const QString& repo_id)
+{
+    return getAccountByRepo(repo_id, seafApplet->rpcClient());
+}
+
+void AccountManager::onAccountsChanged()
+{
+    QMutexLocker cache_lock(&accounts_cache_mutex_);
+    accounts_cache_.clear();
+}
+
+void AccountManager::invalidateCurrentLogin()
+{
+    // make sure we have accounts there
+    if (!hasAccount())
+        return;
+    const Account &account = accounts_.front();
+    // if the token is already invalidated, ignore
+    if (account.token.isEmpty())
+        return;
+
+    emit accountAboutToRelogin(account);
+
+    clearSyncToken(account);
+    clearAccountToken(account);
+    seafApplet->warningBox(tr("Authorization expired, please re-login"));
+
+    emit accountRequireRelogin(account);
+}
+
+bool AccountManager::reloginAccount(const Account &account_in)
+{
+    qWarning("Relogin to account %s", account_in.username.toUtf8().data());
+    bool accepted;
+
+    // Make a copy of the account arugment because it may be released after the
+    // login succeeded.
+    //
+    // See: https://github.com/haiwen/seafile-client/blob/v6.1.3/src/account-mgr.cpp#L219
+    // See: https://gist.github.com/lins05/f952356ba8733d5aa19b54a6db19f69a
+    const Account account(account_in);
+
+    do {
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+        if (account.isShibboleth) {
+            ShibLoginDialog shib_dialog(
+                account.serverUrl, seafApplet->settingsManager()->getComputerName());
+            accepted = shib_dialog.exec() == QDialog::Accepted;
+            break;
+        }
+#endif // HAVE_SHIBBOLETH_SUPPORT
+        LoginDialog dialog;
+        dialog.initFromAccount(account);
+        accepted = dialog.exec() == QDialog::Accepted;
+    } while (0);
+
+    if (accepted) {
+        getSyncedReposToken(account);
+    }
+
+    return accepted;
+}
+
+void AccountManager::getSyncedReposToken(const Account& account)
+{
+    QStringList repo_ids = collectSyncedReposForAccount(account);
+    if (repo_ids.empty()) {
+        return;
+    }
+
+    /* old account object don't contains the new token */
+    QString host = account.serverUrl.host();
+    QString username = account.username;
+    Account new_account = getAccountByHostAndUsername(host, username);
+    if (!new_account.isValid())
+        return;
+
+    // For debugging lots of repos problem.
+    // TODO: Comment this out before committing!!
+    //
+    // int targetNumberForDebug = 300;
+    // while (repo_ids.size() < targetNumberForDebug) {
+    //     repo_ids.append(repo_ids);
+    // }
+    // repo_ids = repo_ids.mid(0, 300);
+    // printf ("repo_ids.size() = %d\n", repo_ids.size());
+
+    sendGetRepoTokensRequet(new_account, repo_ids, 3);
+}
+
+
+void AccountManager::sendGetRepoTokensRequet(const Account& account,
+                                             const QStringList& repo_ids,
+                                             int max_retries)
+{
+    GetRepoTokensRequest *req = new GetRepoTokensRequest(
+        account, repo_ids, max_retries);
+
+    connect(req, SIGNAL(success()),
+            this, SLOT(onGetRepoTokensSuccess()));
+    connect(req, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetRepoTokensFailed(const ApiError&)));
+    req->send();
+}
+
+void AccountManager::onGetRepoTokensSuccess()
+{
+    GetRepoTokensRequest *req = (GetRepoTokensRequest *)(sender());
+    foreach (const QString& repo_id, req->repoTokens().keys()) {
+        seafApplet->rpcClient()->setRepoToken(
+            repo_id, req->repoTokens().value(repo_id));
+    }
+    req->deleteLater();
+}
+
+void AccountManager::onGetRepoTokensFailed(const ApiError& error)
+{
+    GetRepoTokensRequest *req = (GetRepoTokensRequest *)QObject::sender();
+    qWarning("retry get repo tokens request, error = %s", toCStr(error.toString()));
+    seafApplet->warningBox(
+        tr("Failed to get repo sync information from server: %1").arg(error.toString()));
+    if (req->maxRetries() > 0) {
+        sendGetRepoTokensRequet(req->account(), req->repoIds(), req->maxRetries() - 1);
+    }
+    req->deleteLater();
+}
diff --git a/src/account-mgr.h b/src/account-mgr.h
new file mode 100644 (file)
index 0000000..2b39fd8
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef _SEAF_ACCOUNT_MGR_H
+#define _SEAF_ACCOUNT_MGR_H
+
+#include <vector>
+
+#include <QObject>
+#include <QHash>
+#include <QMutex>
+
+#include "account.h"
+
+struct sqlite3;
+struct sqlite3_stmt;
+class ApiError;
+class SeafileRpcClient;
+
+/**
+ * Load/Save seahub accounts
+ */
+class AccountManager : public QObject {
+    Q_OBJECT
+
+public:
+    AccountManager();
+    ~AccountManager();
+
+    int start();
+    void updateServerInfo();
+
+    int saveAccount(const Account& account);
+    int removeAccount(const Account& account);
+
+    void logoutDevice(const Account& account);
+    void logoutDeviceNonautoLogin();
+
+    bool clearAccountToken(const Account& account);
+    bool clearSyncToken(const Account& account);
+    void removeNonautoLoginSyncTokens();
+
+    const std::vector<Account>& loadAccounts();
+    bool accountExists(const QUrl& url, const QString& username);
+
+    bool hasAccount() const { return !accounts_.empty(); }
+
+    Account currentAccount() const { return hasAccount() ? accounts_[0] : Account(); }
+
+    bool setCurrentAccount(const Account& account);
+
+    int replaceAccount(const Account& old_account,
+                       const Account& new_account);
+
+    Account getAccountByHostAndUsername(const QString& host,
+                                        const QString& username) const;
+
+    Account getAccountBySignature(const QString& account_sig) const;
+
+    /// \brief find the Account By Repo ID
+    /// return an invalid Account if failed
+    Account getAccountByRepo(const QString& repo_id);
+
+    // Also used by extension handler
+    Account getAccountByRepo(const QString& repo_id, SeafileRpcClient *rpc);
+
+    void updateAccountInfo(const Account& account, const AccountInfo& info);
+
+    bool validateAndUseAccount(const Account& account);
+
+    // accessors
+    const std::vector<Account>& accounts() const { return accounts_; }
+
+    // invalidate current login and emit a re-login signal
+    void invalidateCurrentLogin();
+
+signals:
+    /**
+     * Account added/removed/switched.
+     */
+    void beforeAccountSwitched();
+    void accountsChanged();
+    void accountAboutToRelogin(const Account& account);
+    void accountRequireRelogin(const Account& account);
+
+    void requireAddAccount();
+    void accountInfoUpdated(const Account& account);
+
+public slots:
+    bool reloginAccount(const Account &account);
+
+private slots:
+    void serverInfoSuccess(const Account &account, const ServerInfo &info);
+    void serverInfoFailed(const ApiError&);
+
+    void onAccountsChanged();
+
+    void onAboutToQuit();
+
+    void onGetRepoTokensSuccess();
+    void onGetRepoTokensFailed(const ApiError& error);
+
+private:
+    Q_DISABLE_COPY(AccountManager)
+
+    void updateServerInfo(unsigned index);
+    static bool loadAccountsCB(struct sqlite3_stmt *stmt, void *data);
+    static bool loadServerInfoCB(struct sqlite3_stmt *stmt, void *data);
+
+    void updateAccountLastVisited(const Account& account);
+    void getSyncedReposToken(const Account& account);
+    void sendGetRepoTokensRequet(const Account& account, const QStringList& repo_ids, int max_retries);
+
+    QHash<QString, Account> accounts_cache_;
+
+    struct sqlite3 *db;
+    std::vector<Account> accounts_;
+
+    QMutex accounts_mutex_;
+    QMutex accounts_cache_mutex_;
+};
+
+#endif  // _SEAF_ACCOUNT_MGR_H
diff --git a/src/account.cpp b/src/account.cpp
new file mode 100644 (file)
index 0000000..42be511
--- /dev/null
@@ -0,0 +1,30 @@
+#include "account.h"
+#include "utils/utils.h"
+#include "api/requests.h"
+
+Account::~Account()
+{
+    if (serverInfoRequest)
+        serverInfoRequest->deleteLater();
+}
+
+ServerInfoRequest* Account::createServerInfoRequest()
+{
+    if (serverInfoRequest)
+        serverInfoRequest->deleteLater();
+    return serverInfoRequest = new ServerInfoRequest(*this);
+}
+
+QUrl Account::getAbsoluteUrl(const QString& relativeUrl) const
+{
+    return ::urlJoin(serverUrl, relativeUrl);
+}
+
+QString Account::getSignature() const
+{
+    if (!isValid()) {
+        return "";
+    }
+
+    return ::md5(serverUrl.host() + username).left(7);
+}
diff --git a/src/account.h b/src/account.h
new file mode 100644 (file)
index 0000000..f2e6a5e
--- /dev/null
@@ -0,0 +1,152 @@
+#ifndef ACCOUNT_H
+#define ACCOUNT_H
+
+#include <QUrl>
+#include <QString>
+#include <QMetaType>
+
+#include "api/server-info.h"
+
+class ServerInfoRequest;
+
+class AccountInfo {
+public:
+    QString email;
+    QString name;
+    qint64 totalStorage;
+    qint64 usedStorage;
+};
+
+class Account {
+    friend class AccountManager;
+    ServerInfoRequest *serverInfoRequest;
+    ServerInfoRequest* createServerInfoRequest();
+public:
+    ServerInfo serverInfo;
+    AccountInfo accountInfo;
+    QUrl serverUrl;
+    QString username;
+    QString token;
+    qint64 lastVisited;
+    bool isShibboleth;
+    bool isAutomaticLogin;
+    QString s2fa_token;
+
+    ~Account();
+    Account() : serverInfoRequest(NULL),
+                serverInfo(),
+                lastVisited(0),
+                isShibboleth(false),
+                isAutomaticLogin(true) {}
+    Account(QUrl serverUrl, QString username, QString token,
+            qint64 lastVisited=0, bool isShibboleth = false,
+            bool isAutomaticLogin = true, QString s2fa_token = QString())
+        : serverInfoRequest(NULL),
+          serverInfo(),
+          accountInfo(),
+          serverUrl(serverUrl),
+          username(username),
+          token(token),
+          lastVisited(lastVisited),
+          isShibboleth(isShibboleth),
+          isAutomaticLogin(isAutomaticLogin),
+          s2fa_token(s2fa_token) {}
+
+    Account(const Account &rhs)
+      : serverInfoRequest(NULL),
+        serverInfo(rhs.serverInfo),
+        accountInfo(rhs.accountInfo),
+        serverUrl(rhs.serverUrl),
+        username(rhs.username),
+        token(rhs.token),
+        lastVisited(rhs.lastVisited),
+        isShibboleth(rhs.isShibboleth),
+        isAutomaticLogin(rhs.isAutomaticLogin),
+        s2fa_token(rhs.s2fa_token)
+    {
+    }
+
+    Account& operator=(const Account&rhs) {
+        serverInfoRequest = NULL;
+        serverInfo = rhs.serverInfo;
+        accountInfo = rhs.accountInfo;
+        serverUrl = rhs.serverUrl;
+        username = rhs.username;
+        token = rhs.token;
+        lastVisited = rhs.lastVisited;
+        isShibboleth = rhs.isShibboleth;
+        isAutomaticLogin = rhs.isAutomaticLogin;
+        s2fa_token = rhs.s2fa_token;
+        return *this;
+    }
+
+    bool operator==(const Account& rhs) const {
+        return serverUrl == rhs.serverUrl
+            && username == rhs.username;
+    }
+
+    bool operator!=(const Account& rhs) const {
+        return !(*this == rhs);
+    }
+
+    bool isValid() const {
+        return token.length() > 0;
+    }
+
+    bool hasS2FAToken() const {
+        return s2fa_token.length() > 0;
+    }
+
+    bool isPro() const {
+        return serverInfo.proEdition;
+    }
+
+    bool hasOfficePreview() const {
+        return serverInfo.officePreview;
+    }
+
+    bool hasFileSearch() const {
+        return serverInfo.fileSearch;
+    }
+
+    bool hasDisableSyncWithAnyFolder() const {
+        return serverInfo.disableSyncWithAnyFolder;
+    }
+
+    bool isAtLeastVersion(unsigned majorVersion, unsigned minorVersion, unsigned patchVersion) const {
+        return (serverInfo.majorVersion << 20) +
+               (serverInfo.minorVersion << 10) +
+               (serverInfo.patchVersion) >=
+               (majorVersion << 20) + (minorVersion << 10) + (patchVersion);
+    }
+
+    int getEncryptedLibraryVersion() {
+        return serverInfo.encryptedLibraryVersion;
+    }
+    // require pro edtions and version at least at ...
+    // excluding OSS Version
+    bool isAtLeastProVersion(unsigned majorVersion, unsigned minorVersion, unsigned patchVersion) const {
+        return isPro() && isAtLeastVersion(majorVersion, minorVersion, patchVersion);
+    }
+
+    // require oss edtions and version at least at ...
+    // excluding Pro Version
+    bool isAtLeastOSSVersion(unsigned majorVersion, unsigned minorVersion, unsigned patchVersion) const {
+        return !isPro() && isAtLeastVersion(majorVersion, minorVersion, patchVersion);
+    }
+
+    qint32 getTotalStorage() const {
+        return accountInfo.totalStorage;
+    }
+    
+    qint32 getUsedStorage() const {
+        return accountInfo.usedStorage;
+    }
+
+    QUrl getAbsoluteUrl(const QString& relativeUrl) const;
+    QString getSignature() const;
+};
+
+Q_DECLARE_METATYPE(Account)
+
+#endif // ACCOUNT_H
diff --git a/src/api/api-client.cpp b/src/api/api-client.cpp
new file mode 100644 (file)
index 0000000..4172ebe
--- /dev/null
@@ -0,0 +1,361 @@
+#include <QUrl>
+#include <QtNetwork>
+#include <QSslError>
+#include <QSslConfiguration>
+#include <QSslCertificate>
+#include <QNetworkConfigurationManager>
+
+#include "seafile-applet.h"
+#include "customization-service.h"
+#include "certs-mgr.h"
+#include "ui/main-window.h"
+#include "ui/ssl-confirm-dialog.h"
+#include "utils/utils.h"
+#include "network-mgr.h"
+#include "server-status-service.h"
+
+#include "api-client.h"
+
+namespace {
+
+const char *kContentTypeForm = "application/x-www-form-urlencoded";
+const char *kAuthHeader = "Authorization";
+const char *kSeafileClientVersionHeader = "X-Seafile-Client-Version";
+
+const int kMaxRedirects = 3;
+const int kMaxHttpErrorLogLen = 300;
+
+bool shouldIgnoreRequestError(const QNetworkReply* reply)
+{
+    return reply->url().toString().contains("/api2/events");
+}
+
+QString getQueryValue(const QUrl& url, const QString& name)
+{
+    QString v;
+    v = QUrlQuery(url.query()).queryItemValue(name);
+    return QUrl::fromPercentEncoding(v.toUtf8());
+}
+
+QNetworkAccessManager *createQNAM() {
+    QNetworkAccessManager *manager = new QNetworkAccessManager(qApp);
+    NetworkManager::instance()->addWatch(manager);
+    manager->setCache(CustomizationService::instance()->diskCache());
+
+    // From: http://www.qtcentre.org/threads/37514-use-of-QNetworkAccessManager-networkAccessible
+    //
+    // QNetworkAccessManager::networkAccessible is not explicitly set when the
+    // QNetworkAccessManager is created. It is only set after the network
+    // session is initialized. The session is initialized automatically when you
+    // make a network request or you can initialize it before hand with
+    // QNetworkAccessManager::setConfiguration() or the
+    // QNetworkConfigurationManager::NetworkSessionRequired flag is set.
+    manager->setConfiguration(
+        QNetworkConfigurationManager().defaultConfiguration());
+    return manager;
+}
+
+} // namespace
+
+QNetworkAccessManager* SeafileApiClient::qnam_ = nullptr;
+void SeafileApiClient::resetQNAM()
+{
+    if (qnam_) {
+        qnam_->deleteLater();
+    }
+    qnam_ = createQNAM();
+}
+
+SeafileApiClient::SeafileApiClient(QObject *parent)
+    : QObject(parent),
+      reply_(NULL),
+      redirect_count_(0),
+      use_cache_(false)
+{
+    if (!qnam_) {
+        qnam_ = createQNAM();
+    }
+    connect(qnam_, SIGNAL(destroyed(QObject *)),
+            this, SLOT(doAbort()));
+}
+
+void SeafileApiClient::doAbort()
+{
+    if (reply_ && reply_->isRunning()) {
+        qWarning("aborting api request %s on network error", toCStr(reply_->url().toString()));
+        reply_->abort();
+    }
+}
+
+SeafileApiClient::~SeafileApiClient()
+{
+}
+
+void SeafileApiClient::prepareRequest(QNetworkRequest *req)
+{
+    if (use_cache_) {
+        req->setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork);
+        req->setAttribute(QNetworkRequest::CacheSaveControlAttribute, true);
+    } else {
+        req->setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
+        req->setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
+    }
+    if (token_.length() > 0) {
+        char buf[1024];
+        qsnprintf(buf, sizeof(buf), "Token %s", token_.toUtf8().data());
+        req->setRawHeader(kAuthHeader, buf);
+    }
+
+    foreach (const QString& key, headers_.keys()) {
+        req->setRawHeader(key.toUtf8().data(), headers_[key].toUtf8().data());
+    }
+
+    req->setRawHeader(kSeafileClientVersionHeader, STRINGIZE(SEAFILE_CLIENT_VERSION));
+}
+
+void SeafileApiClient::get(const QUrl& url)
+{
+    QNetworkRequest request(url);
+    prepareRequest(&request);
+
+    reply_ = qnam_->get(request);
+    // By default the parent object of the reply instance would be the
+    // QNetworkAccessManager, and we delete the reply in our destructor. But now
+    // we may recreate the QNetworkAccessManager when the connection status is
+    // changed, which means the reply may already have been deleted when the
+    // destructor is called. To avoid this, we explicitly set the
+    // SeafileApiClient as the parent object of the reply.
+    reply_->setParent(this);
+
+    connect(reply_, SIGNAL(sslErrors(const QList<QSslError>&)),
+            this, SLOT(onSslErrors(const QList<QSslError>&)));
+
+    connect(reply_, SIGNAL(finished()), this, SLOT(httpRequestFinished()));
+}
+
+void SeafileApiClient::post(const QUrl& url, const QByteArray& data, bool is_put)
+{
+    body_ = data;
+    QNetworkRequest request(url);
+    prepareRequest(&request);
+
+    request.setHeader(QNetworkRequest::ContentTypeHeader, kContentTypeForm);
+
+    if (is_put)
+        reply_ = qnam_->put(request, body_);
+    else
+        reply_ = qnam_->post(request, body_);
+
+    reply_->setParent(this);
+
+    connect(reply_, SIGNAL(finished()), this, SLOT(httpRequestFinished()));
+
+    connect(reply_, SIGNAL(sslErrors(const QList<QSslError>&)),
+            this, SLOT(onSslErrors(const QList<QSslError>&)));
+}
+
+void SeafileApiClient::deleteResource(const QUrl& url)
+{
+    QNetworkRequest request(url);
+    prepareRequest(&request);
+
+    reply_ = qnam_->deleteResource(request);
+    reply_->setParent(this);
+
+    connect(reply_, SIGNAL(sslErrors(const QList<QSslError>&)),
+            this, SLOT(onSslErrors(const QList<QSslError>&)));
+
+    connect(reply_, SIGNAL(finished()), this, SLOT(httpRequestFinished()));
+}
+
+void SeafileApiClient::onSslErrors(const QList<QSslError>& errors)
+{
+    const QUrl url = reply_->url();
+    CertsManager *mgr = seafApplet->certsManager();
+    Q_FOREACH(const QSslError &error, errors) {
+        const QSslCertificate &cert = error.certificate();
+
+        if (cert.isNull()) {
+            // The server has no ssl certificate, we do nothing and let the
+            // request fail
+            // it is a fatal error, no way to recover
+            qWarning("the certificate for %s is null", url.toString().toUtf8().data());
+            break;
+        }
+
+        QSslCertificate saved_cert = mgr->getCertificate(url.toString());
+
+        if (saved_cert.isNull()) {
+            // dump certificate information
+            qWarning() << "\n= SslError =\n" << error.errorString();
+            qWarning() << dumpCipher(reply_->sslConfiguration().sessionCipher());
+            qWarning() << dumpCertificate(cert);
+
+            // This is the first time when the client connects to the server.
+            if (seafApplet->detailedYesOrNoBox(
+                tr("<b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?"),
+                error.errorString() + "\n" + dumpCertificate(cert), 0, false)) {
+                mgr->saveCertificate(url, cert);
+                // TODO handle ssl by verifying certificate chain instead
+                reply_->ignoreSslErrors();
+            }
+            break;
+        } else if (saved_cert == cert) {
+            // The user has choosen to trust the certificate before
+            // TODO handle ssl by verifying certificate chain instead
+            reply_->ignoreSslErrors();
+            break;
+        } else {
+            // dump certificate information
+            qWarning() << "\n= SslError =\n" << error.errorString();
+            qWarning() << dumpCipher(reply_->sslConfiguration().sessionCipher());
+            qWarning() << dumpCertificate(cert);
+            qWarning() << dumpCertificate(saved_cert);
+
+            /**
+             * The cert which the user had chosen to trust has been changed. It
+             * may be either:
+             *
+             * 1. The server has changed its ssl certificate
+             * 2. The user's connection is under security attack
+             *
+             * Anyway, we'll prompt the user
+             */
+            SslConfirmDialog dialog(url, cert, saved_cert, seafApplet->mainWindow());
+            if (dialog.exec() == QDialog::Accepted) {
+                // TODO handle ssl by verifying certificate chain instead
+                reply_->ignoreSslErrors();
+                if (dialog.rememberChoice()) {
+                    mgr->saveCertificate(url, cert);
+                }
+            } else {
+                reply_->abort();
+                break;
+            }
+            break;
+        }
+    }
+}
+
+void SeafileApiClient::httpRequestFinished()
+{
+    int code = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+    if (code == 0 && reply_->error() != QNetworkReply::NoError) {
+        if (NetworkManager::instance()->shouldRetry(reply_->error())) {
+            qWarning("[api] network proxy error, retrying\n");
+            resendRequest(reply_->url());
+            return;
+        }
+
+        ServerStatusService::instance()->updateOnFailedRequest(reply_->url());
+        NetworkStatusDetector::instance()->setNetworkFailure(reply_->error());
+
+        if (!shouldIgnoreRequestError(reply_)) {
+            qWarning("[api] network error for %s: %s\n", toCStr(reply_->url().toString()),
+                   reply_->errorString().toUtf8().data());
+        }
+        emit networkError(reply_->error(), reply_->errorString());
+        return;
+    }
+
+    ServerStatusService::instance()->updateOnSuccessfullRequest(reply_->url());
+    NetworkStatusDetector::instance()->setNetworkSuccess();
+
+    if (handleHttpRedirect()) {
+        return;
+    }
+
+    if ((code / 100) == 4 || (code / 100) == 5) {
+        if (!shouldIgnoreRequestError(reply_)) {
+            QByteArray content = reply_->readAll();
+            qWarning("request failed for %s: %s\n",
+                     reply_->url().toString().toUtf8().data(),
+                     content.left(kMaxHttpErrorLogLen).data());
+            if (content.length() > kMaxHttpErrorLogLen) {
+                qDebug("request failed for %s: %s\n",
+                       reply_->url().toString().toUtf8().data(),
+                       content.data());
+            }
+        }
+        emit requestFailed(code);
+        return;
+    }
+
+    emit requestSuccess(*reply_);
+}
+
+// Return true if the request is redirected and request is resended.
+bool SeafileApiClient::handleHttpRedirect()
+{
+    QVariant redirect_attr = reply_->attribute(QNetworkRequest::RedirectionTargetAttribute);
+    if (redirect_attr.isNull()) {
+        return false;
+    }
+
+    QUrl redirect_url = redirect_attr.toUrl();
+    if (redirect_url.isRelative()) {
+        redirect_url =  reply_->url().resolved(redirect_url);
+    }
+
+    // printf("redirect to %s (from %s)\n", redirect_url.toString().toUtf8().data(),
+    //        reply_->url().toString().toUtf8().data());
+    if (reply_->operation() == QNetworkAccessManager::PostOperation) {
+        // XXX: Special case for rename/move file api, which returns 301 on
+        // success. We need to distinguish that from a normal 301 redirect.
+        // (In contrast, Rename/move dir api returns 200 on success).
+        if (redirect_url.path().contains(QRegExp("/api2/repos/[^/]+/file/"))) {
+            QString old_name = getQueryValue(reply_->url(), "p");
+            QString new_name = getQueryValue(redirect_url, "p");
+            // Only treat it as a rename file success when old and new are different
+            if (!old_name.isEmpty() && !new_name.isEmpty() && old_name != new_name) {
+                // printf ("get 301 rename file success, old_name: %s, new_name: %s\n",
+                //         toCStr(old_name), toCStr(new_name));
+                return false;
+            }
+        }
+    }
+
+
+    if (redirect_count_++ > kMaxRedirects) {
+        // simply treat too many redirects as server side error
+        emit requestFailed(500);
+        qWarning("too many redirects for %s\n",
+               reply_->url().toString().toUtf8().data());
+        return true;
+    }
+
+    resendRequest(redirect_url);
+
+    return true;
+}
+
+void SeafileApiClient::resendRequest(const QUrl& url)
+{
+    switch (reply_->operation()) {
+    case QNetworkAccessManager::GetOperation:
+        reply_->deleteLater();
+        get(url);
+        break;
+    case QNetworkAccessManager::PostOperation:
+        post(url, body_, false);
+        break;
+    case QNetworkAccessManager::PutOperation:
+        post(url, body_, true);
+        break;
+    case QNetworkAccessManager::DeleteOperation:
+        reply_->deleteLater();
+        deleteResource(url);
+        break;
+    default:
+        reply_->deleteLater();
+        qWarning() << "unsupported operation" << reply_->operation()
+          << "to" << url.toString()
+          << "from" << reply_->url().toString();
+        break;
+    }
+}
+
+void SeafileApiClient::setHeader(const QString& key, const QString& value)
+{
+    headers_[key] = value;
+}
diff --git a/src/api/api-client.h b/src/api/api-client.h
new file mode 100644 (file)
index 0000000..927a399
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef SEAFILE_API_CLIENT_H
+#define SEAFILE_API_CLIENT_H
+
+#include <QHash>
+#include <QString>
+#include <QObject>
+#include <QNetworkReply>
+
+#include "account.h"
+#include "server-repo.h"
+
+class QNetworkAccessManager;
+class QSslError;
+
+/**
+ * SeafileApiClient handles the underlying api mechanism
+ */
+class SeafileApiClient : public QObject {
+    Q_OBJECT
+
+public:
+    SeafileApiClient(QObject *parent=0);
+    ~SeafileApiClient();
+    void setToken(const QString& token) { token_ = token; };
+    void setHeader(const QString& key, const QString& value);
+    void get(const QUrl& url);
+    void post(const QUrl& url, const QByteArray& body, bool is_put);
+    void deleteResource(const QUrl& url);
+    void setUseCache(bool use_cache) { use_cache_ = use_cache; }
+
+    const QNetworkReply* reply() const { return reply_; }
+
+    static QNetworkAccessManager *qnam_;
+    static void resetQNAM();
+
+signals:
+    void requestSuccess(QNetworkReply& reply);
+    void requestFailed(int code);
+    void networkError(const QNetworkReply::NetworkError& error, const QString& error_string);
+
+private slots:
+    void httpRequestFinished();
+    void onSslErrors(const QList<QSslError>& errors);
+    void doAbort();
+
+private:
+    Q_DISABLE_COPY(SeafileApiClient)
+
+    bool handleHttpRedirect();
+    bool handleRedirectForNonGetRequest();
+    void prepareRequest(QNetworkRequest *req);
+
+    void resendRequest(const QUrl& url);
+
+    QString token_;
+
+    QByteArray body_;
+
+    QNetworkReply *reply_;
+
+    int redirect_count_;
+    bool use_cache_;
+
+    QHash<QString, QString> headers_;
+};
+
+#endif  // SEAFILE_API_CLIENT_H
diff --git a/src/api/api-error.cpp b/src/api/api-error.cpp
new file mode 100644 (file)
index 0000000..3dcd500
--- /dev/null
@@ -0,0 +1,101 @@
+#include "api-error.h"
+
+ApiError::ApiError()
+{
+    ssl_reply_ = NULL;
+}
+
+ApiError ApiError::fromNetworkError(const QNetworkReply::NetworkError& network_error,
+                                    const QString& network_error_string)
+{
+    ApiError error;
+
+    error.type_ = NETWORK_ERROR;
+    error.network_error_ = network_error;
+    error.network_error_string_ = network_error_string;
+
+    return error;
+}
+
+ApiError ApiError::fromSslErrors(QNetworkReply *reply, const QList<QSslError>& ssl_errors)
+{
+    ApiError error;
+
+    error.type_ = SSL_ERROR;
+    error.ssl_reply_ = reply;
+    error.ssl_errors_ = ssl_errors;
+
+    return error;
+}
+
+ApiError ApiError::fromHttpError(int code)
+{
+    ApiError error;
+
+    error.type_ = HTTP_ERROR;
+    error.http_error_code_ = code;
+
+    return error;
+}
+
+ApiError ApiError::fromJsonError()
+{
+    ApiError error;
+
+    error.type_ = HTTP_ERROR;
+    // 500 internal server error
+    error.http_error_code_ = 500;
+
+    return error;
+}
+
+QString ApiError::toString() const {
+    switch (type_) {
+    case SSL_ERROR:
+        return QObject::tr("SSL Error");
+    case NETWORK_ERROR:
+        return QObject::tr("Network Error: %1").arg(network_error_string_);
+    case HTTP_ERROR:
+        if (http_error_code_ == 443) {
+            return QObject::tr("The storage quota has been used up");
+        } else {
+            return QObject::tr("Server Error");
+        }
+    default:
+        // impossible
+        break;
+    }
+
+    return "";
+}
+
+ApiError ApiError::NoError() {
+    ApiError error;
+    error.type_ = NOT_AN_ERROR;
+    return error;
+}
+
+bool ApiError::operator==(const ApiError& other)
+{
+    if (type_ != other.type_) {
+        return false;
+    }
+
+    bool same;
+    switch (type_) {
+    case NOT_AN_ERROR:
+        same = true;
+        break;
+    case HTTP_ERROR:
+        same = http_error_code_ == other.http_error_code_;
+        break;
+    case NETWORK_ERROR:
+        same = network_error_ == other.network_error_;
+        break;
+    case SSL_ERROR:
+        same = ssl_errors_ == other.ssl_errors_;
+        break;
+    }
+
+    return same;
+}
diff --git a/src/api/api-error.h b/src/api/api-error.h
new file mode 100644 (file)
index 0000000..e64784b
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef SEAFILE_API_ERROR_H
+#define SEAFILE_API_ERROR_H
+
+#include <QString>
+#include <QNetworkReply>
+#include <QList>
+#include <QSslError>
+
+#include "server-repo.h"
+
+class QNetworkAccessManager;
+class QByteArray;
+
+/**
+ * Error info in an api request.
+ */
+class ApiError {
+public:
+    enum ErrorType {
+        NOT_AN_ERROR = 0,
+        // network error, like connection refused
+        NETWORK_ERROR,
+        // ssl error, like invalid ssl certificate
+        SSL_ERROR,
+        // http error, like 4xx, 5xx
+        HTTP_ERROR,
+    };
+
+    static ApiError fromNetworkError(const QNetworkReply::NetworkError& error, const QString& error_string);
+    static ApiError fromSslErrors(QNetworkReply *reply, const QList<QSslError>& errors);
+    static ApiError fromHttpError(int code);
+    static ApiError fromJsonError();
+    static ApiError NoError();
+
+    // accessors
+    ErrorType type() const { return type_; }
+
+    const QNetworkReply::NetworkError& networkError() const { return network_error_; }
+    const QString& networkErrorString() const { return network_error_string_; }
+
+    QNetworkReply *sslReply() const { return ssl_reply_; }
+    const QList<QSslError>& sslErrors() const { return ssl_errors_; }
+
+    int httpErrorCode() const { return http_error_code_; }
+
+    QString toString() const;
+
+    bool operator==(const ApiError& other);
+
+    bool operator!=(const ApiError& other) {
+        return !(*this == other);
+    }
+
+private:
+    ApiError();
+
+    ErrorType type_;
+
+    int http_error_code_;
+
+    QNetworkReply::NetworkError network_error_;
+    QString network_error_string_;
+
+    QNetworkReply *ssl_reply_;
+    QList<QSslError> ssl_errors_;
+};
+
+#endif  // SEAFILE_API_ERROR_H
diff --git a/src/api/api-request.cpp b/src/api/api-request.cpp
new file mode 100644 (file)
index 0000000..53b06a5
--- /dev/null
@@ -0,0 +1,112 @@
+#include <QtGlobal>
+#include <QtNetwork>
+#include <QUrlQuery>
+
+#include "utils/utils.h"
+#include "api-client.h"
+#include "api-error.h"
+
+#include "api-request.h"
+
+SeafileApiRequest::SeafileApiRequest(const QUrl& url, Method method,
+                                     const QString& token)
+    : url_(url),
+      method_(method),
+      token_(token)
+{
+    api_client_ = new SeafileApiClient;
+}
+
+SeafileApiRequest::~SeafileApiRequest()
+{
+    if (api_client_) {
+        api_client_->deleteLater();
+        api_client_ = nullptr;
+    }
+}
+
+void SeafileApiRequest::setUrlParam(const QString& name, const QString& value)
+{
+    params_[name] = value;
+}
+
+void SeafileApiRequest::setFormParam(const QString& name, const QString& value)
+{
+    if (method_ != METHOD_PUT && method_ != METHOD_POST) {
+        qWarning("warning: calling setFormParam on a request with method %d\n", method_);
+    }
+    form_params_[name] = value;
+}
+
+void SeafileApiRequest::setUseCache(bool use_cache)
+{
+    api_client_->setUseCache(use_cache);
+}
+
+void SeafileApiRequest::setHeader(const QString& key, const QString& value)
+{
+    api_client_->setHeader(key, value);
+}
+
+void SeafileApiRequest::send()
+{
+    if (token_.size() > 0) {
+        api_client_->setToken(token_);
+    }
+
+    if (!params_.isEmpty()) {
+        url_ = ::includeQueryParams(url_, params_);
+    }
+
+    QByteArray post_data;
+
+    switch (method_) {
+    case METHOD_GET:
+        api_client_->get(url_);
+        break;
+    case METHOD_DELETE:
+        api_client_->deleteResource(url_);
+        break;
+    case METHOD_POST:
+    case METHOD_PUT:
+        post_data = ::buildFormData(form_params_);
+        api_client_->post(url_, post_data, method_ == METHOD_PUT);
+        break;
+    default:
+        qWarning("unknown method %d\n", method_);
+        return;
+    }
+
+    connect(api_client_, SIGNAL(requestSuccess(QNetworkReply&)),
+            this, SLOT(requestSuccess(QNetworkReply&)));
+
+    connect(api_client_, SIGNAL(networkError(const QNetworkReply::NetworkError&, const QString&)),
+            this, SLOT(onNetworkError(const QNetworkReply::NetworkError&, const QString&)));
+
+    connect(api_client_, SIGNAL(requestFailed(int)),
+            this, SLOT(onHttpError(int)));
+}
+
+void SeafileApiRequest::onHttpError(int code)
+{
+    emit failed(ApiError::fromHttpError(code));
+}
+
+void SeafileApiRequest::onNetworkError(const QNetworkReply::NetworkError& error, const QString& error_string)
+{
+    emit failed(ApiError::fromNetworkError(error, error_string));
+}
+
+
+json_t* SeafileApiRequest::parseJSON(QNetworkReply &reply, json_error_t *error)
+{
+    QByteArray raw = reply.readAll();
+    //qWarning("\n%s\n", raw.data());
+    json_t *root = json_loads(raw.data(), 0, error);
+    return root;
+}
+
+const QNetworkReply* SeafileApiRequest::reply() const
+{
+    return api_client_->reply();
+}
diff --git a/src/api/api-request.h b/src/api/api-request.h
new file mode 100644 (file)
index 0000000..2c6015d
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef SEAFILE_API_REQUEST_H
+#define SEAFILE_API_REQUEST_H
+
+#include <jansson.h>
+
+#include <QObject>
+#include <QUrl>
+#include <QMap>
+#include <QPair>
+#include <QList>
+#include <QNetworkReply>
+#include <QHash>
+
+class SeafileApiClient;
+class QSslError;
+class ApiError;
+
+/**
+ * Abstract base class for all types of api requests
+ */
+class SeafileApiRequest : public QObject {
+    Q_OBJECT
+
+public:
+    virtual ~SeafileApiRequest();
+
+    const QUrl& url() const { return url_; }
+
+    // set param k-v pair which appears in query params
+    void setUrlParam(const QString& name, const QString& value);
+    // set param k-v pair which appears in url-encoded form
+    void setFormParam(const QString& name, const QString& value);
+    // useful for static resources like images
+    void setUseCache(bool use_cache);
+
+    void setHeader(const QString& key, const QString& value);
+
+    virtual void send();
+
+    const QNetworkReply* reply() const;
+
+signals:
+    void failed(const ApiError& error);
+
+protected slots:
+    virtual void requestSuccess(QNetworkReply& reply) = 0;
+    void onNetworkError(const QNetworkReply::NetworkError& error, const QString& error_string);
+    void onHttpError(int);
+
+protected:
+    enum Method {
+        // post action, passing urlParam and formParam
+        METHOD_POST,
+        // get action, passing urlParam only
+        METHOD_GET,
+        // put action, passing urlParam and formParam
+        METHOD_PUT,
+        // delete action, passing urlParam only
+        METHOD_DELETE
+    };
+
+    SeafileApiRequest(const QUrl& url,
+                      const Method method,
+                      const QString& token = QString());
+
+    json_t* parseJSON(QNetworkReply &reply, json_error_t *error);
+
+    // Used with QScopedPointer for json_t
+    struct JsonPointerCustomDeleter {
+        static inline void cleanup(json_t *json) {
+            json_decref(json);
+        }
+    };
+
+private:
+    Q_DISABLE_COPY(SeafileApiRequest)
+
+    QUrl url_;
+    QHash<QString, QString> params_;
+    QHash<QString, QString> form_params_;
+    Method method_;
+    QString token_;
+    SeafileApiClient* api_client_;
+};
+
+#endif // SEAFILE_API_REQUEST_H
diff --git a/src/api/commit-details.cpp b/src/api/commit-details.cpp
new file mode 100644 (file)
index 0000000..cc5bd53
--- /dev/null
@@ -0,0 +1,97 @@
+#include <glib.h>
+#include <glib-object.h>
+
+#include "commit-details.h"
+
+
+namespace {
+
+QString getStringFromJsonArray(const json_t *array, size_t index)
+{
+    return QString::fromUtf8(json_string_value(json_array_get(array, index)));
+}
+
+void processFileList(const json_t *json, const char *key, std::vector<QString> *files)
+{
+    json_t *array = json_object_get(json, key);
+    if (array) {
+        for (int i = 0, n = json_array_size(array); i < n; i++) {
+            QString name = getStringFromJsonArray(array, i);
+            files->push_back(name);
+        }
+    }
+}
+
+} // namespace
+
+
+CommitDetails CommitDetails::fromJSON(const json_t *json, json_error_t */* error */)
+{
+    CommitDetails details;
+
+    processFileList(json, "added_files", &details.added_files);
+    processFileList(json, "deleted_files", &details.deleted_files);
+    processFileList(json, "modified_files", &details.modified_files);
+
+    processFileList(json, "added_dirs", &details.added_dirs);
+    processFileList(json, "deleted_dirs", &details.deleted_dirs);
+
+    // process renamed files
+    json_t *array = json_object_get(json, "renamed_files");
+    if (array) {
+        for (int i = 0, n = json_array_size(array); i < n; i += 2) {
+            QString before_rename = getStringFromJsonArray(array, i);
+            QString after_rename = getStringFromJsonArray(array, i + 1);
+            std::pair<QString, QString> pair(before_rename, after_rename);
+            details.renamed_files.push_back(pair);
+        }
+    }
+
+    return details;
+}
+
+
+CommitDetails CommitDetails::fromObjList(const GList *objlist)
+{
+    CommitDetails details;
+
+    for (const GList *ptr = objlist; ptr; ptr = ptr->next) {
+        GObject *obj = (GObject *)(ptr->data);
+        char *c_status = NULL;
+        char *c_name = NULL;
+        char *c_new_name = NULL;
+        g_object_get(obj,
+                     "status",
+                     &c_status,
+                     "name",
+                     &c_name,
+                     "new_name",
+                     &c_new_name,
+                     NULL);
+
+        QString status(c_status);
+        QString name(c_name);
+        QString new_name(c_new_name);
+
+        // printf("%s\n%s\n%s\n",
+        //        status.toUtf8().data(),
+        //        name.toUtf8().data(),
+        //        new_name.toUtf8().data());
+
+        if (status == "add") {
+            details.added_files.push_back(name);
+        } else if (status == "del") {
+            details.deleted_files.push_back(name);
+        } else if (status == "mov") {
+            details.renamed_files.push_back({name, new_name});
+        } else if (status == "mod") {
+            details.modified_files.push_back(name);
+        } else if (status == "newdir") {
+            details.added_dirs.push_back(name);
+        } else if (status == "deldir") {
+            details.deleted_dirs.push_back(name);
+        }
+    }
+
+    return details;
+}
diff --git a/src/api/commit-details.h b/src/api/commit-details.h
new file mode 100644 (file)
index 0000000..da973f0
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SEAFILE_CLIENT_API_COMMIT_DETAILS_H
+#define SEAFILE_CLIENT_API_COMMIT_DETAILS_H
+
+#include <jansson.h>
+
+#include <vector>
+#include <utility>
+
+#include <QString>
+#include <QMetaType>
+
+struct _GList;
+
+class CommitDetails {
+public:
+    std::vector<QString> added_files, deleted_files, modified_files, added_dirs, deleted_dirs;
+
+    // renamed or moved files
+    std::vector<std::pair<QString, QString> > renamed_files;
+
+    static CommitDetails fromJSON(const json_t*, json_error_t *error);
+    static CommitDetails fromObjList(const _GList *objlist);
+};
+
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(CommitDetails)
+
+#endif // SEAFILE_CLIENT_API_COMMIT_DETAILS_H
diff --git a/src/api/contact-share-info.cpp b/src/api/contact-share-info.cpp
new file mode 100644 (file)
index 0000000..8ec8543
--- /dev/null
@@ -0,0 +1,6 @@
+#include <QHash>
+#include "contact-share-info.h"
+
+uint qHash(const SeafileUser& user, uint seed) {
+    return qHash(user.email, seed);
+}
diff --git a/src/api/contact-share-info.h b/src/api/contact-share-info.h
new file mode 100644 (file)
index 0000000..da2a70f
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef SEAFILE_CLIENT_CONTACT_SHARE_INFO_H
+#define SEAFILE_CLIENT_CONTACT_SHARE_INFO_H
+
+#include <QMetaType>
+#include <QString>
+
+struct SeafileGroup {
+    int id;
+    QString name;
+    QString owner;
+    bool isValid() const { return !name.isEmpty(); }
+};
+
+struct SeafileUser {
+    QString avatar_url;
+    QString email;
+    // Optional fields;
+    QString contact_email;
+    QString name;
+
+    bool operator==(const SeafileUser& rhs) const {
+        return rhs.email == email;
+    }
+
+    QString getDisplayEmail() const {
+        return !contact_email.isEmpty() ? contact_email : email;
+    }
+
+    bool isValid() const { return !email.isEmpty(); }
+};
+
+uint qHash(const SeafileUser& user, uint seed=0);
+
+enum SharePermission {
+    READ_WRITE,
+    READ_ONLY,
+};
+
+
+enum ShareType {
+    SHARE_TO_USER,
+    SHARE_TO_GROUP,
+};
+
+
+inline SharePermission permissionfromString(const QString& s)
+{
+    return s == "r" ? READ_ONLY : READ_WRITE;
+}
+
+inline ShareType shareTypeFromString(const QString& s)
+{
+    return s == "group" ? SHARE_TO_GROUP : SHARE_TO_USER;
+}
+
+struct UserShareInfo {
+    SharePermission permission;
+    SeafileUser user;
+};
+
+struct GroupShareInfo {
+    SharePermission permission;
+    SeafileGroup group;
+};
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(SeafileGroup)
+Q_DECLARE_METATYPE(SeafileUser)
+Q_DECLARE_METATYPE(UserShareInfo)
+Q_DECLARE_METATYPE(GroupShareInfo)
+
+#endif // SEAFILE_CLIENT_CONTACT_SHARE_INFO_H
diff --git a/src/api/event.cpp b/src/api/event.cpp
new file mode 100644 (file)
index 0000000..f4f2fda
--- /dev/null
@@ -0,0 +1,143 @@
+#include <jansson.h>
+
+#include <vector>
+
+#include "utils/translate-commit-desc.h"
+
+
+#include "event.h"
+
+#include <QDateTime>
+
+namespace {
+
+QString getStringFromJson(const json_t *json, const char* key)
+{
+    return QString::fromUtf8(json_string_value(json_object_get(json, key)));
+}
+
+const char *kEventTypeRepoCreate = "repo-create";
+const char *kEventTypeRepoDelete = "repo-delete";
+
+} // namespace
+
+
+SeafEvent SeafEvent::fromJSON(const json_t *json, json_error_t */* error */)
+{
+    SeafEvent event;
+
+    event.author = getStringFromJson(json, "author");
+    if (event.author.isEmpty()) {
+        event.author = "anonymous";
+        event.anonymous = true;
+    } else {
+        event.anonymous = false;
+    }
+
+    event.nick = getStringFromJson(json, "nick");
+    if (event.nick.isEmpty()) {
+        event.nick = "anonymous";
+    }
+
+    event.repo_id = getStringFromJson(json, "repo_id");
+    event.repo_name = getStringFromJson(json, "repo_name");
+
+    event.commit_id = getStringFromJson(json, "commit_id");
+    event.etype = getStringFromJson(json, "etype");
+    event.desc = getStringFromJson(json, "desc");
+
+    event.timestamp = json_integer_value(json_object_get(json, "time"));
+
+    if (event.etype == kEventTypeRepoCreate) {
+        event.desc = QObject::tr("Created library \"%1\"").arg(event.repo_name);
+    } else if (event.etype == kEventTypeRepoDelete) {
+        event.desc = QObject::tr("Deleted library \"%1\"").arg(event.repo_name);
+    }
+
+    event.desc = translateCommitDesc(event.desc);
+
+    // For testing long lines of event description.
+    // event.desc += event.desc + event.desc;
+
+    return event;
+}
+
+// parser seafile new file activities json
+SeafEvent SeafEvent::fromJSONV2(const json_t *json, json_error_t */* error */)
+{
+    SeafEvent event;
+
+    event.author = getStringFromJson(json, "author_email");
+    if (event.author.isEmpty()) {
+        event.author = "anonymous";
+        event.anonymous = true;
+    } else {
+        event.anonymous = false;
+    }
+
+    event.nick = getStringFromJson(json, "author_name");
+    if (event.nick.isEmpty()) {
+        event.nick = "anonymous";
+    }
+
+    event.repo_id = getStringFromJson(json, "repo_id");
+    event.repo_name = getStringFromJson(json, "repo_name");
+    event.commit_id = getStringFromJson(json, "commit_id");
+    event.etype = getStringFromJson(json, "op_type");
+    event.is_use_new_activities_api = true;
+
+    QString time = getStringFromJson(json, "time");
+    event.timestamp = QDateTime::fromString(time, Qt::ISODate).toMSecsSinceEpoch() / 1000;
+
+    QString path = getStringFromJson(json, "path");
+    QString file_name = getStringFromJson(json, "name");
+    QString obj_type = getStringFromJson(json, "obj_type");
+    QString old_name = getStringFromJson(json, "old_name");
+    QString old_path = getStringFromJson(json, "old_path");
+    QString old_repo_name = getStringFromJson(json, "old_repo_name");
+    bool ok;
+    int clean_trash_days = getStringFromJson(json, "days").toInt(&ok);
+
+    QString out_obj_desc, out_op_desc;
+    translateCommitDescV2(path, file_name, event.repo_name, obj_type,
+                          event.etype, old_repo_name, old_path,
+                          old_name, clean_trash_days, &out_obj_desc,
+                          &out_op_desc);
+    event.desc = out_obj_desc;
+    event.op_desc = out_op_desc;
+
+    return event;
+}
+
+std::vector<SeafEvent> SeafEvent::listFromJSON(const json_t *json, json_error_t *error, bool is_use_new_json_parser)
+{
+    std::vector<SeafEvent> events;
+
+    for (size_t i = 0; i < json_array_size(json); i++) {
+        SeafEvent event;
+        if (!is_use_new_json_parser) {
+            event = fromJSON(json_array_get(json, i), error);
+        } else {
+            event = fromJSONV2(json_array_get(json, i), error);
+        }
+
+        events.push_back(event);
+    }
+
+    return events;
+}
+
+QString SeafEvent::toString() const
+{
+    return QString("type=\"%1\",author=\"%2\",repo_name=\"%3\",desc=\"%4\",commit=\"%5\"")
+        .arg(etype).arg(author).arg(repo_name).arg(desc).arg(commit_id);
+}
+
+bool SeafEvent::isDetailsDisplayable() const
+{
+    if (commit_id.isEmpty()) {
+        return false;
+    }
+    // TODO: determine if there are files change in this commit
+    return true;
+}
diff --git a/src/api/event.h b/src/api/event.h
new file mode 100644 (file)
index 0000000..310395a
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef SEAFILE_CLIENT_API_EVENT_H
+#define SEAFILE_CLIENT_API_EVENT_H
+
+#include <jansson.h>
+#include <vector>
+
+#include <QObject>
+#include <QString>
+#include <QMetaType>
+
+class SeafEvent {
+public:
+    QString author;
+    QString nick;
+    QString repo_id;
+    QString repo_name;
+    QString etype;
+    QString commit_id;
+    QString desc;
+    QString op_desc;
+    qint64 timestamp;
+    bool is_use_new_activities_api;
+
+    // true for events like a file upload by unregistered user from a
+    // uploadable link
+    bool anonymous;
+
+    bool isDetailsDisplayable() const;
+    
+    static SeafEvent fromJSON(const json_t*, json_error_t *error);
+    static SeafEvent fromJSONV2(const json_t*, json_error_t *error);
+    static std::vector<SeafEvent> listFromJSON(const json_t*, json_error_t *json, bool is_use_new_json_parser = false);
+
+    QString toString() const;
+};
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(SeafEvent)
+
+#endif // SEAFILE_CLIENT_API_EVENT_H
diff --git a/src/api/requests.cpp b/src/api/requests.cpp
new file mode 100644 (file)
index 0000000..40a6ae5
--- /dev/null
@@ -0,0 +1,1430 @@
+#include <jansson.h>
+
+#include <QScopedPointer>
+#include <QtNetwork>
+
+#include "account.h"
+
+#include "api-error.h"
+#include "commit-details.h"
+#include "event.h"
+#include "repo-service.h"
+#include "rpc/rpc-client.h"
+#include "seafile-applet.h"
+#include "server-repo.h"
+#include "starred-file.h"
+#include "utils/api-utils.h"
+#include "utils/json-utils.h"
+#include "utils/utils.h"
+
+#include "requests.h"
+
+namespace
+{
+const char* kApiPingUrl = "api2/ping/";
+const char* kApiLoginUrl = "api2/auth-token/";
+const char* kListReposUrl = "api2/repos/";
+const char* kCreateRepoUrl = "api2/repos/";
+const char* kGetRepoUrl = "api2/repos/%1/";
+const char* kCreateSubrepoUrl = "api2/repos/%1/dir/sub_repo/";
+const char* kUnseenMessagesUrl = "api2/unseen_messages/";
+const char* kDefaultRepoUrl = "api2/default-repo/";
+const char* kStarredFilesUrl = "api2/starredfiles/";
+const char* kStarredItemsUrl = "api/v2.1/starred-items/";
+const char* kGetEventsUrl = "api2/events/";
+const char* kCommitDetailsUrl = "api2/repo_history_changes/";
+const char* kAvatarUrl = "api2/avatars/user/";
+const char* kSetRepoPasswordUrl = "api2/repos/";
+const char* kServerInfoUrl = "api2/server-info/";
+const char* kLogoutDeviceUrl = "api2/logout-device/";
+const char* kGetRepoTokensUrl = "api2/repo-tokens/";
+const char* kGetLoginTokenUrl = "api2/client-login/";
+const char* kFileSearchUrl = "api2/search/";
+const char* kAccountInfoUrl = "api2/account/info/";
+const char* kDirSharedItemsUrl = "api2/repos/%1/dir/shared_items/";
+const char* kRepoSharedUrl = "api2/beshared-repos/%1/";
+const char* kFetchGroupsAndContactsUrl = "api2/groupandcontacts/";
+const char* kFetchGroupsUrl = "api2/groups/";
+const char* kRemoteWipeReportUrl = "api2/device-wiped/";
+const char* kSearchUsersUrl = "api2/search-user/";
+const char* kGetThumbnailUrl = "api2/repos/%1/thumbnail/";
+const char* kCreateFileUploadLink = "api/v2.1/upload-links/";
+
+const char* kGetFileActivitiesUrl = "api/v2.1/activities/";
+} // namespace
+
+
+PingServerRequest::PingServerRequest(const QUrl& serverAddr)
+
+    : SeafileApiRequest(::urlJoin(serverAddr, kApiPingUrl),
+                        SeafileApiRequest::METHOD_GET)
+{
+}
+
+void PingServerRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success();
+}
+
+/**
+ * LoginRequest
+ */
+LoginRequest::LoginRequest(const QUrl& serverAddr,
+                           const QString& username,
+                           const QString& password,
+                           const QString& computer_name)
+
+    : SeafileApiRequest(::urlJoin(serverAddr, kApiLoginUrl),
+                        SeafileApiRequest::METHOD_POST)
+{
+    setFormParam("username", username);
+    setFormParam("password", password);
+
+    QHash<QString, QString> params = ::getSeafileLoginParams(computer_name);
+    foreach (const QString& key, params.keys()) {
+        setFormParam(key, params[key]);
+    }
+}
+
+void LoginRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QString s2fa_token = reply.rawHeader("X-SEAFILE-S2FA");
+    const char* token =
+        json_string_value(json_object_get(json.data(), "token"));
+    if (token == NULL) {
+        qWarning("failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    emit success(token, s2fa_token);
+}
+
+
+/**
+ * ListReposRequest
+ */
+ListReposRequest::ListReposRequest(const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kListReposUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token)
+{
+}
+
+void ListReposRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("ListReposRequest:failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    std::vector<ServerRepo> repos =
+        ServerRepo::listFromJSON(json.data(), &error);
+    emit success(repos);
+}
+
+
+/**
+ * DownloadRepoRequest
+ */
+DownloadRepoRequest::DownloadRepoRequest(const Account& account,
+                                         const QString& repo_id,
+                                         bool read_only)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl("api2/repos/" + repo_id + "/download-info/"),
+          SeafileApiRequest::METHOD_GET,
+          account.token),
+      read_only_(read_only)
+{
+}
+
+RepoDownloadInfo RepoDownloadInfo::fromDict(QMap<QString, QVariant>& dict,
+                                            const QUrl& url_in,
+                                            bool read_only)
+{
+    RepoDownloadInfo info;
+    info.repo_version = dict["repo_version"].toInt();
+    info.relay_id = dict["relay_id"].toString();
+    info.relay_addr = dict["relay_addr"].toString();
+    info.relay_port = dict["relay_port"].toString();
+    info.email = dict["email"].toString();
+    info.token = dict["token"].toString();
+    info.repo_id = dict["repo_id"].toString();
+    info.repo_name = dict["repo_name"].toString();
+    info.encrypted = dict["encrypted"].toInt();
+    info.magic = dict["magic"].toString();
+    info.random_key = dict["random_key"].toString();
+    info.enc_version = dict.value("enc_version", 1).toInt();
+    info.readonly = read_only;
+
+    QUrl url = url_in;
+    url.setPath("/");
+    info.relay_addr = url.host();
+
+    QString salt = dict.value("salt").toString();
+    QMap<QString, QVariant> map;
+    map.insert("is_readonly", read_only ? 1 : 0);
+    map.insert("server_url", url.toString());
+    map.insert("repo_salt", salt);
+
+    info.more_info = ::mapToJson(map);
+
+    return info;
+}
+
+void DownloadRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+    RepoDownloadInfo info = RepoDownloadInfo::fromDict(dict, url(), read_only_);
+
+    emit success(info);
+}
+
+/**
+ * GetRepoRequest
+ */
+GetRepoRequest::GetRepoRequest(const Account& account, const QString& repoid)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kGetRepoUrl).arg(repoid)),
+          SeafileApiRequest::METHOD_GET,
+          account.token),
+      repoid_(repoid)
+{
+}
+
+void GetRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+    ServerRepo repo = ServerRepo::fromJSON(root, &error);
+
+    emit success(repo);
+}
+
+/**
+ * CreateRepoRequest
+ */
+CreateRepoRequest::CreateRepoRequest(const Account& account,
+                                     const QString& name,
+                                     const QString& desc,
+                                     const QString& passwd)
+    : SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
+                        SeafileApiRequest::METHOD_POST,
+                        account.token)
+{
+    setFormParam(QString("name"), name);
+    setFormParam(QString("desc"), desc);
+    if (!passwd.isNull()) {
+        qWarning("Encrypted repo");
+        setFormParam(QString("passwd"), passwd);
+    }
+}
+
+CreateRepoRequest::CreateRepoRequest(const Account& account,
+                                     const QString& name,
+                                     const QString& desc,
+                                     int enc_version,
+                                     const QString& repo_id,
+                                     const QString& magic,
+                                     const QString& random_key)
+    : SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
+                        SeafileApiRequest::METHOD_POST,
+                        account.token)
+{
+    setFormParam("name", name);
+    setFormParam("desc", desc);
+    setFormParam("enc_version", QString::number(enc_version));
+    setFormParam("repo_id", repo_id);
+    setFormParam("magic", magic);
+    setFormParam("random_key", random_key);
+}
+
+CreateRepoRequest::CreateRepoRequest(const Account& account,
+                                     const QString& name,
+                                     const QString& desc,
+                                     int enc_version,
+                                     const QString& repo_id,
+                                     const QString& magic,
+                                     const QString& random_key,
+                                     const QString& salt)
+    : SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
+                        SeafileApiRequest::METHOD_POST,
+                        account.token)
+{
+    setFormParam("name", name);
+    setFormParam("desc", desc);
+    setFormParam("enc_version", QString::number(enc_version));
+    setFormParam("repo_id", repo_id);
+    setFormParam("magic", magic);
+    setFormParam("random_key", random_key);
+    setFormParam("salt", salt);
+}
+
+void CreateRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+    RepoDownloadInfo info = RepoDownloadInfo::fromDict(dict, url(), false);
+
+    emit success(info);
+}
+
+/**
+ * CreateSubrepoRequest
+ */
+CreateSubrepoRequest::CreateSubrepoRequest(const Account& account,
+                                           const QString& name,
+                                           const QString& repoid,
+                                           const QString& path,
+                                           const QString& passwd)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kCreateSubrepoUrl).arg(repoid)),
+          SeafileApiRequest::METHOD_GET,
+          account.token)
+{
+    setUrlParam(QString("p"), path);
+    setUrlParam(QString("name"), name);
+    if (!passwd.isNull()) {
+        setUrlParam(QString("password"), passwd);
+    }
+}
+
+void CreateSubrepoRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+    emit success(dict["sub_repo_id"].toString());
+}
+
+/**
+ * GetUnseenSeahubNotificationsRequest
+ */
+GetUnseenSeahubNotificationsRequest::GetUnseenSeahubNotificationsRequest(
+    const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kUnseenMessagesUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token)
+{
+}
+
+void GetUnseenSeahubNotificationsRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning(
+            "GetUnseenSeahubNotificationsRequest: failed to parse json:%s\n",
+            error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QMap<QString, QVariant> ret = mapFromJSON(root, &error);
+
+    if (!ret.contains("count")) {
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    int count = ret.value("count").toInt();
+    emit success(count);
+}
+
+GetDefaultRepoRequest::GetDefaultRepoRequest(const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kDefaultRepoUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token)
+{
+}
+
+void GetDefaultRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("CreateDefaultRepoRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+    if (!dict.contains("exists")) {
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    bool exists = dict.value("exists").toBool();
+    if (!exists) {
+        emit success(false, "");
+        return;
+    }
+
+    if (!dict.contains("repo_id")) {
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QString repo_id = dict.value("repo_id").toString();
+
+    emit success(true, repo_id);
+}
+
+
+CreateDefaultRepoRequest::CreateDefaultRepoRequest(const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kDefaultRepoUrl),
+                        SeafileApiRequest::METHOD_POST,
+                        account.token)
+{
+}
+
+void CreateDefaultRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("CreateDefaultRepoRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+    if (!dict.contains("repo_id")) {
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    emit success(dict.value("repo_id").toString());
+}
+
+GetStarredFilesRequest::GetStarredFilesRequest(const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kStarredFilesUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token)
+{
+}
+
+void GetStarredFilesRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("GetStarredFilesRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    std::vector<StarredItem> files =
+        StarredItem::listFromJSON(json.data(), &error);
+    emit success(files);
+}
+
+GetStarredFilesRequestV2::GetStarredFilesRequestV2(const Account& account)
+        : SeafileApiRequest(account.getAbsoluteUrl(kStarredItemsUrl),
+                            SeafileApiRequest::METHOD_GET,
+                            account.token)
+{
+}
+
+void GetStarredFilesRequestV2::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("GetStarredItemsRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+    json_t* array = json_object_get(json.data(), "starred_item_list");
+    std::vector<StarredItem> files =
+            StarredItem::listFromJSON(array, &error, true);
+    emit success(files);
+}
+
+// Seafile get file activities api v2.1
+// page default value is 1
+// perpage defult value is 25
+// avatar size defult value is 72, old api is 36
+GetEventsRequestV2::GetEventsRequestV2(const Account& account, int page, int perpage, int avatar_size)
+    : SeafileApiRequest(account.getAbsoluteUrl(kGetFileActivitiesUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token)
+{
+    setUrlParam("page", QString::number(page));
+    setUrlParam("avatar_size", QString::number(avatar_size));
+}
+
+void GetEventsRequestV2::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("GetEventsRequestV2: failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    json_t* array = json_object_get(json.data(), "events");
+    std::vector<SeafEvent> events = SeafEvent::listFromJSON(array, &error, true);
+
+    emit success(events);
+}
+
+GetEventsRequest::GetEventsRequest(const Account& account, int start)
+    : SeafileApiRequest(account.getAbsoluteUrl(kGetEventsUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token)
+{
+    if (start > 0) {
+        setUrlParam("start", QString::number(start));
+    }
+}
+
+void GetEventsRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("GetEventsRequest: failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    bool more = false;
+    int more_offset = -1;
+
+    json_t* array = json_object_get(json.data(), "events");
+    std::vector<SeafEvent> events = SeafEvent::listFromJSON(array, &error);
+
+    more = json_is_true(json_object_get(json.data(), "more"));
+    if (more) {
+        more_offset =
+            json_integer_value(json_object_get(json.data(), "more_offset"));
+    }
+
+    emit success(events, more_offset);
+}
+
+GetCommitDetailsRequest::GetCommitDetailsRequest(const Account& account,
+                                                 const QString& repo_id,
+                                                 const QString& commit_id)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(kCommitDetailsUrl + repo_id + "/"),
+          SeafileApiRequest::METHOD_GET,
+          account.token)
+{
+    setUrlParam("commit_id", commit_id);
+}
+
+void GetCommitDetailsRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("GetCommitDetailsRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    CommitDetails details = CommitDetails::fromJSON(json.data(), &error);
+
+    emit success(details);
+}
+
+// /api2/user/foo@foo.com/resized/36
+GetAvatarRequest::GetAvatarRequest(const Account& account,
+                                   const QString& email,
+                                   qint64 mtime,
+                                   int size)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(kAvatarUrl + email + "/resized/" +
+                                 QString::number(size) + "/"),
+          SeafileApiRequest::METHOD_GET,
+          account.token),
+      fetch_img_req_(NULL),
+      mtime_(mtime)
+{
+    account_ = account;
+    email_ = email;
+}
+
+GetAvatarRequest::~GetAvatarRequest()
+{
+    if (fetch_img_req_) {
+        fetch_img_req_->deleteLater();
+        fetch_img_req_ = nullptr;
+    }
+}
+
+void GetAvatarRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("GetAvatarRequest: failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    const char* avatar_url =
+        json_string_value(json_object_get(json.data(), "url"));
+
+    // we don't need to fetch all images if we have latest one
+    json_t* mtime = json_object_get(json.data(), "mtime");
+    if (!mtime) {
+        qWarning("GetAvatarRequest: no 'mtime' value in response\n");
+    }
+    else {
+        qint64 new_mtime = json_integer_value(mtime);
+        // When mtime_ < 0 it means there is no local cache yet
+        if (mtime_ >= 0 && new_mtime == mtime_) {
+            emit success(QImage());
+            return;
+        }
+        mtime_ = new_mtime;
+    }
+
+    if (!avatar_url) {
+        qWarning("GetAvatarRequest: no 'url' value in response\n");
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QString url = QUrl::fromPercentEncoding(avatar_url);
+
+    fetch_img_req_ = new FetchImageRequest(url);
+
+    connect(fetch_img_req_, SIGNAL(failed(const ApiError&)), this,
+            SIGNAL(failed(const ApiError&)));
+    connect(fetch_img_req_, SIGNAL(success(const QImage&)), this,
+            SIGNAL(success(const QImage&)));
+    fetch_img_req_->send();
+}
+
+FetchImageRequest::FetchImageRequest(const QString& img_url)
+    : SeafileApiRequest(QUrl(img_url), SeafileApiRequest::METHOD_GET)
+{
+}
+
+void FetchImageRequest::requestSuccess(QNetworkReply& reply)
+{
+    QImage img;
+    img.loadFromData(reply.readAll());
+
+    if (img.isNull()) {
+        qWarning("FetchImageRequest: invalid image data\n");
+        emit failed(ApiError::fromHttpError(400));
+    }
+    else {
+        emit success(img);
+    }
+}
+
+SetRepoPasswordRequest::SetRepoPasswordRequest(const Account& account,
+                                               const QString& repo_id,
+                                               const QString& password)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(kSetRepoPasswordUrl + repo_id + "/"),
+          SeafileApiRequest::METHOD_POST,
+          account.token)
+{
+    setFormParam("password", password);
+}
+
+void SetRepoPasswordRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success();
+}
+
+ServerInfoRequest::ServerInfoRequest(const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kServerInfoUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token),
+      account_(account)
+{
+}
+
+void ServerInfoRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+    ServerInfo ret;
+
+    if (dict.contains("version")) {
+        ret.parseVersionFromString(dict["version"].toString());
+    }
+
+    if (dict.contains("encrypted_library_version")) {
+        ret.parseEncryptedLibraryVersionFromString(dict["encrypted_library_version"].toString());
+    }
+
+    if (dict.contains("features")) {
+        ret.parseFeatureFromStrings(dict["features"].toStringList());
+    }
+
+    if (dict.contains("desktop-custom-logo")) {
+        ret.customLogo = dict["desktop-custom-logo"].toString();
+    }
+
+    if (dict.contains("desktop-custom-brand")) {
+        ret.customBrand = dict["desktop-custom-brand"].toString();
+    }
+
+    emit success(account_, ret);
+}
+
+LogoutDeviceRequest::LogoutDeviceRequest(const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kLogoutDeviceUrl),
+                        SeafileApiRequest::METHOD_POST,
+                        account.token),
+      account_(account)
+{
+}
+
+void LogoutDeviceRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success();
+}
+
+GetRepoTokensRequest::GetRepoTokensRequest(const Account& account,
+                                           const QStringList& repo_ids,
+                                           int max_retries,
+                                           int batch_size)
+    : SeafileApiRequest(account.getAbsoluteUrl(kGetRepoTokensUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token),
+      account_(account),
+      repo_ids_(repo_ids),
+      max_retries_(max_retries),
+      batch_offset_(0),
+      batch_size_(batch_size)
+{
+}
+
+void GetRepoTokensRequest::send()
+{
+    doNextBatch();
+}
+
+void GetRepoTokensRequest::doNextBatch()
+{
+    if (batch_offset_ >= repo_ids_.size()) {
+        emit success();
+        return;
+    }
+
+    int count;
+    count = qMin(batch_size_, repo_ids_.size() - batch_offset_);
+    batch_req_.reset(new SingleBatchRepoTokensRequest(
+        account_, repo_ids_.mid(batch_offset_, count)));
+
+    connect(batch_req_.data(),
+            SIGNAL(failed(const ApiError &)),
+            this,
+            SIGNAL(failed(const ApiError &)));
+    connect(batch_req_.data(), SIGNAL(success()), this, SLOT(batchSuccess()));
+    batch_req_->send();
+
+    // printf("sending request for one batch: offset = %d, count = %d\n",
+    //        batch_offset_,
+    //        count);
+}
+
+void GetRepoTokensRequest::batchSuccess()
+{
+    const QMap<QString, QString>& tokens = batch_req_->repoTokens();
+
+    // printf ("one batch finished, offset = %d, count = %d\n", batch_offset_, tokens.size());
+
+    repo_tokens_.unite(tokens);
+    batch_offset_ += batch_req_->repoIds().size();
+    doNextBatch();
+}
+
+void GetRepoTokensRequest::requestSuccess(QNetworkReply& reply)
+{
+    // Just a place holder. A `GetRepoTokensRequest` is a wrapper around a
+    // series of `SingleBatchRepoTokensRequest`, which really sends the api
+    // requests.
+}
+
+SingleBatchRepoTokensRequest::SingleBatchRepoTokensRequest(const Account& account,
+                                           const QStringList& repo_ids)
+    : SeafileApiRequest(account.getAbsoluteUrl(kGetRepoTokensUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token),
+      repo_ids_(repo_ids)
+{
+    setUrlParam("repos", repo_ids.join(","));
+}
+
+void SingleBatchRepoTokensRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("SingleBatchRepoTokensRequest: failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+    foreach (const QString& repo_id, dict.keys()) {
+        repo_tokens_[repo_id] = dict[repo_id].toString();
+    }
+
+    emit success();
+}
+
+GetLoginTokenRequest::GetLoginTokenRequest(const Account& account,
+                                           const QString& next_url)
+    : SeafileApiRequest(account.getAbsoluteUrl(kGetLoginTokenUrl),
+                        SeafileApiRequest::METHOD_POST,
+                        account.token),
+      account_(account),
+      next_url_(next_url)
+{
+}
+
+void GetLoginTokenRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("GetLoginTokenRequest: failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+    if (!dict.contains("token")) {
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+    emit success(dict["token"].toString());
+}
+
+FileSearchRequest::FileSearchRequest(const Account& account,
+                                     const QString& keyword,
+                                     int page,
+                                     int per_page,
+                                     const QString& repo_id)
+    : SeafileApiRequest(account.getAbsoluteUrl(kFileSearchUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token),
+      keyword_(keyword),
+      page_(page)
+{
+    setUrlParam("q", keyword_);
+    if (page > 0) {
+        setUrlParam("page", QString::number(page));
+    }
+    // per_page = 2;
+    setUrlParam("per_page", QString::number(per_page));
+    if (!repo_id.isEmpty()) {
+        setUrlParam("search_repo", repo_id);
+    }
+}
+
+void FileSearchRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("FileSearchResult: failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+    if (!dict.contains("results")) {
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+    QList<QVariant> results = dict["results"].toList();
+    std::vector<FileSearchResult> retval;
+    Q_FOREACH(const QVariant& result, results)
+    {
+        FileSearchResult tmp;
+        QMap<QString, QVariant> map = result.toMap();
+        if (map.empty())
+            continue;
+        tmp.repo_id = map["repo_id"].toString();
+        tmp.repo_name = RepoService::instance()->getRepo(tmp.repo_id).name;
+        tmp.name = map["name"].toString();
+        tmp.oid = map["oid"].toString();
+        tmp.last_modified = map["last_modified"].toLongLong();
+        tmp.fullpath = map["fullpath"].toString();
+        tmp.size = map["size"].toLongLong();
+        tmp.is_dir = map["is_dir"].toBool();
+        retval.push_back(tmp);
+    }
+    bool has_more = dict["has_more"].toBool();
+    bool is_loading_more = page_ > 1;
+
+    emit success(retval, is_loading_more, has_more);
+}
+
+FetchCustomLogoRequest::FetchCustomLogoRequest(const QUrl& url)
+    : SeafileApiRequest(url, SeafileApiRequest::METHOD_GET)
+{
+    setUseCache(true);
+}
+
+void FetchCustomLogoRequest::requestSuccess(QNetworkReply& reply)
+{
+    QPixmap logo;
+    logo.loadFromData(reply.readAll());
+
+    if (logo.isNull()) {
+        qWarning("FetchCustomLogoRequest: invalid image data\n");
+        emit failed(ApiError::fromHttpError(400));
+    }
+    else {
+        emit success(url());
+    }
+}
+
+FetchAccountInfoRequest::FetchAccountInfoRequest(const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kAccountInfoUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token)
+{
+    account_ = account;
+}
+
+void FetchAccountInfoRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("FetchAccountInfoRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+    AccountInfo info;
+    info.email = dict["email"].toString();
+    info.name = dict["name"].toString();
+    info.totalStorage = dict["total"].toLongLong();
+    info.usedStorage = dict["usage"].toLongLong();
+    if (info.name.isEmpty()) {
+        info.name = dict["nickname"].toString();
+    }
+    emit success(info);
+}
+
+PrivateShareRequest::PrivateShareRequest(const Account& account,
+                                         const QString& repo_id,
+                                         const QString& path,
+                                         const SeafileUser& user,
+                                         int group_id,
+                                         SharePermission permission,
+                                         ShareType share_type,
+                                         ShareOperation op)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kDirSharedItemsUrl).arg(repo_id)),
+          op == UPDATE_SHARE ? METHOD_POST : (op == REMOVE_SHARE ? METHOD_DELETE
+                                                                 : METHOD_PUT),
+          account.token),
+      group_id_(share_type == SHARE_TO_GROUP ? group_id : -1),
+      user_(share_type == SHARE_TO_USER ? user: SeafileUser()),
+      permission_(permission),
+      share_type_(share_type),
+      share_operation_(op)
+{
+    setUrlParam("p", path);
+    setFormParam("permission", permission == READ_ONLY ? "r" : "rw");
+    bool is_add = op == ADD_SHARE;
+    if (is_add) {
+        setFormParam("share_type",
+                     share_type == SHARE_TO_USER ? "user" : "group");
+    }
+    else {
+        setUrlParam("share_type",
+                    share_type == SHARE_TO_USER ? "user" : "group");
+    }
+
+    if (share_type == SHARE_TO_USER) {
+        if (is_add) {
+            setFormParam("username", user_.email);
+        }
+        else {
+            setUrlParam("username", user_.email);
+        }
+    }
+    else {
+        if (is_add) {
+            setFormParam("group_id", QString::number(group_id));
+        }
+        else {
+            setUrlParam("group_id", QString::number(group_id));
+        }
+    }
+}
+
+void PrivateShareRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("PrivateShareRequest: failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    emit success();
+}
+
+
+FetchGroupsAndContactsRequest::FetchGroupsAndContactsRequest(
+    const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kFetchGroupsAndContactsUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token)
+{
+}
+
+void FetchGroupsAndContactsRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("FetchGroupsAndContactsRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QList<SeafileGroup> groups;
+    QList<SeafileUser> contacts;
+
+    json_t* groups_array = json_object_get(json.data(), "groups");
+    if (groups_array) {
+        int i, n = json_array_size(groups_array);
+        for (i = 0; i < n; i++) {
+            json_t* group_object = json_array_get(groups_array, i);
+            const char* name =
+                json_string_value(json_object_get(group_object, "name"));
+            int group_id =
+                json_integer_value(json_object_get(group_object, "id"));
+            if (name && group_id) {
+                SeafileGroup group;
+                group.id = group_id;
+                group.name = QString::fromUtf8(name);
+                const char* owner =
+                    json_string_value(json_object_get(group_object, "creator"));
+                if (owner) {
+                    group.owner = QString::fromUtf8(owner);
+                }
+                groups.push_back(group);
+            }
+        }
+    }
+
+    json_t* contacts_array = json_object_get(json.data(), "contacts");
+    if (contacts_array) {
+        int i, n = json_array_size(contacts_array);
+
+        for (i = 0; i < n; i++) {
+            json_t* contact_object = json_array_get(contacts_array, i);
+            const char* email =
+                json_string_value(json_object_get(contact_object, "email"));
+            if (email) {
+                SeafileUser contact;
+                contact.email = QString::fromUtf8(email);
+                contact.name = QString::fromUtf8(
+                    json_string_value(json_object_get(contact_object, "name")));
+                contacts.push_back(contact);
+            }
+        }
+    }
+
+    emit success(groups, contacts);
+}
+
+GetPrivateShareItemsRequest::GetPrivateShareItemsRequest(const Account& account,
+                                                         const QString& repo_id,
+                                                         const QString& path)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kDirSharedItemsUrl).arg(repo_id)),
+          SeafileApiRequest::METHOD_GET,
+          account.token)
+{
+    setUrlParam("p", path);
+}
+
+void GetPrivateShareItemsRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("GetPrivateShareItemsRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QList<GroupShareInfo> group_shares;
+    QList<UserShareInfo> user_shares;
+
+    int i, n = json_array_size(json.data());
+    for (i = 0; i < n; i++) {
+        json_t* share_info_object = json_array_get(json.data(), i);
+        Json share_info(share_info_object);
+        QString share_type = share_info.getString("share_type");
+        QString permission = share_info.getString("permission");
+        if (share_type == "group") {
+            // group share
+            Json group = share_info.getObject("group_info");
+            GroupShareInfo group_share;
+            group_share.group.id = group.getLong("id");
+            group_share.group.name = group.getString("name");
+            group_share.permission = ::permissionfromString(permission);
+            group_shares.push_back(group_share);
+        }
+        else if (share_type == "user") {
+            Json user = share_info.getObject("user_info");
+            UserShareInfo user_share;
+            user_share.user.email = user.getString("name");
+            user_share.user.name = user.getString("nickname");
+            user_share.permission = ::permissionfromString(permission);
+            user_shares.push_back(user_share);
+        }
+    }
+
+    emit success(group_shares, user_shares);
+}
+
+RemoteWipeReportRequest::RemoteWipeReportRequest(const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kRemoteWipeReportUrl),
+                        SeafileApiRequest::METHOD_POST)
+{
+    setFormParam(QString("token"), account.token);
+}
+
+void RemoteWipeReportRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success();
+}
+
+SearchUsersRequest::SearchUsersRequest(
+    const Account& account, const QString& pattern)
+    : SeafileApiRequest(account.getAbsoluteUrl(kSearchUsersUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token),
+      pattern_(pattern)
+{
+    setUrlParam("q", pattern);
+}
+
+void SearchUsersRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("SearchUsersRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QList<SeafileUser> users;
+
+    json_t* users_array = json_object_get(json.data(), "users");
+    if (users_array) {
+        int i, n = json_array_size(users_array);
+
+        for (i = 0; i < n; i++) {
+            json_t* user_object = json_array_get(users_array, i);
+            const char* email =
+                json_string_value(json_object_get(user_object, "email"));
+            if (email) {
+                SeafileUser user;
+                user.email = QString::fromUtf8(email);
+                user.name = QString::fromUtf8(
+                    json_string_value(json_object_get(user_object, "name")));
+                user.contact_email = QString::fromUtf8(
+                    json_string_value(json_object_get(user_object, "contact_email")));
+                user.avatar_url = QString::fromUtf8(
+                    json_string_value(json_object_get(user_object, "avatar_url")));
+                users.push_back(user);
+            }
+        }
+    }
+
+    emit success(users);
+}
+
+
+FetchGroupsRequest::FetchGroupsRequest(
+    const Account& account)
+    : SeafileApiRequest(account.getAbsoluteUrl(kFetchGroupsUrl),
+                        SeafileApiRequest::METHOD_GET,
+                        account.token)
+{
+    setUrlParam("with_msg", "false");
+}
+
+void FetchGroupsRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("FetchGroupsRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QList<SeafileGroup> groups;
+
+    int i, n = json_array_size(json.data());
+    for (i = 0; i < n; i++) {
+        json_t* group_object = json_array_get(json.data(), i);
+        const char* name =
+            json_string_value(json_object_get(group_object, "name"));
+        int group_id =
+            json_integer_value(json_object_get(group_object, "id"));
+        if (name && group_id) {
+            SeafileGroup group;
+            group.id = group_id;
+            group.name = QString::fromUtf8(name);
+            const char* owner =
+                json_string_value(json_object_get(group_object, "creator"));
+            if (owner) {
+                group.owner = QString::fromUtf8(owner);
+            }
+            groups.push_back(group);
+        }
+    }
+
+    emit success(groups);
+}
+
+GetThumbnailRequest::GetThumbnailRequest(const Account& account,
+                                         const QString& repo_id,
+                                         const QString& path,
+                                        const QString& dirent_id,
+                                         uint size)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kGetThumbnailUrl).arg(repo_id)),
+          SeafileApiRequest::METHOD_GET,
+          account.token),
+      account_(account),
+      repo_id_(repo_id),
+      path_(path),
+      dirent_id_(dirent_id),
+      size_(size)
+{
+    setUrlParam("p", path);
+    setUrlParam("size", QString::number(size));
+    setUseCache(true);
+}
+
+void GetThumbnailRequest::requestSuccess(QNetworkReply& reply)
+{
+    QPixmap pixmap;
+    pixmap.loadFromData(reply.readAll());
+
+    if (pixmap.isNull()) {
+        qWarning("GetThumbnailRequest: invalid image data\n");
+        emit failed(ApiError::fromHttpError(400));
+    }
+    else {
+        emit success(pixmap);
+    }
+}
+
+UnshareRepoRequest::UnshareRepoRequest(const Account& account,
+                                       const QString& repo_id,
+                                       const QString& from_user)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kRepoSharedUrl).arg(repo_id)),
+          SeafileApiRequest::METHOD_DELETE,
+          account.token),
+      repo_id_(repo_id)
+{
+    setUrlParam("share_type", "personal");
+    setUrlParam("from", from_user);
+}
+
+void UnshareRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success();
+}
+
+CreateFileUploadLinkRequest::CreateFileUploadLinkRequest(const Account& account,
+                                                         const QString &repo_id,
+                                                         const QString &path,
+                                                         const QString &password)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kCreateFileUploadLink)),
+          SeafileApiRequest::METHOD_POST, account.token),
+      repo_id_(repo_id),
+      path_(path),
+      password_(password)
+{
+    setFormParam(QString("repo_id"), repo_id);
+    setFormParam(QString("path"), path);
+    if (!password.isNull()) {
+        setFormParam(QString("password"), password);
+    }
+}
+
+void CreateFileUploadLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+    UploadLinkInfo link_info;
+    link_info.username = dict["username"].toString();
+    link_info.repo_id = dict["repo_id"].toString();
+    link_info.ctime = dict["ctime"].toString();
+    link_info.token = dict["token"].toString();
+    link_info.link = dict["link"].toString();
+    link_info.path = dict["path"].toString();
+
+    emit success(link_info);
+}
+
+GetUploadFileLinkRequest::GetUploadFileLinkRequest(const QString& link)
+    : SeafileApiRequest(link, SeafileApiRequest::METHOD_GET)
+{
+}
+
+void GetUploadFileLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+    QString reply_content(dict["upload_link"].toString());
+
+    do {
+        if (reply_content.size() <= 2)
+            break;
+        QUrl new_url(reply_content);
+        if (!new_url.isValid())
+            break;
+
+        emit success(reply_content);
+        return;
+    } while (0);
+    emit failed(ApiError::fromHttpError(500));
+}
diff --git a/src/api/requests.h b/src/api/requests.h
new file mode 100644 (file)
index 0000000..30353bc
--- /dev/null
@@ -0,0 +1,896 @@
+#ifndef SEAFILE_CLIENT_API_REQUESTS_H
+#define SEAFILE_CLIENT_API_REQUESTS_H
+
+#include <QMap>
+#include <QScopedPointer>
+#include <vector>
+
+#include "account.h"
+#include "api-request.h"
+#include "contact-share-info.h"
+#include "server-repo.h"
+#include "server-repo.h"
+
+class QNetworkReply;
+class QImage;
+class QStringList;
+
+class ServerRepo;
+class Account;
+class StarredItem;
+class SeafEvent;
+class CommitDetails;
+
+class PingServerRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    PingServerRequest(const QUrl& serverAddr);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+signals:
+    void success();
+
+private:
+    Q_DISABLE_COPY(PingServerRequest)
+};
+
+class LoginRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+
+public:
+    LoginRequest(const QUrl& serverAddr,
+                 const QString& username,
+                 const QString& password,
+                 const QString& computer_name);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+signals:
+    void success(const QString& token, const QString& s2fa_token);
+
+private:
+    Q_DISABLE_COPY(LoginRequest)
+};
+
+
+class ListReposRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+
+public:
+    explicit ListReposRequest(const Account& account);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+signals:
+    void success(const std::vector<ServerRepo>& repos);
+
+private:
+    Q_DISABLE_COPY(ListReposRequest)
+};
+
+
+class RepoDownloadInfo
+{
+public:
+    int repo_version;
+    QString relay_id;
+    QString relay_addr;
+    QString relay_port;
+    QString email;
+    QString token;
+    QString repo_id;
+    QString repo_name;
+    bool encrypted;
+    bool readonly;
+    int enc_version;
+    QString magic;
+    QString random_key;
+    QString more_info;
+
+    static RepoDownloadInfo fromDict(QMap<QString, QVariant>& dict,
+                                     const QUrl& url,
+                                     bool read_only);
+};
+
+class DownloadRepoRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+
+public:
+    explicit DownloadRepoRequest(const Account& account,
+                                 const QString& repo_id,
+                                 bool read_only);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+signals:
+    void success(const RepoDownloadInfo& info);
+
+private:
+    Q_DISABLE_COPY(DownloadRepoRequest)
+
+    bool read_only_;
+};
+
+class GetRepoRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+
+public:
+    explicit GetRepoRequest(const Account& account, const QString& repoid);
+    const QString& repoid()
+    {
+        return repoid_;
+    }
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+signals:
+    void success(const ServerRepo& repo);
+
+private:
+    Q_DISABLE_COPY(GetRepoRequest)
+    const QString repoid_;
+};
+
+class CreateRepoRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+
+public:
+    CreateRepoRequest(const Account& account,
+                      const QString& name,
+                      const QString& desc,
+                      const QString& passwd);
+    CreateRepoRequest(const Account& account,
+                      const QString& name,
+                      const QString& desc,
+                      int enc_version,
+                      const QString& repo_id,
+                      const QString& magic,
+                      const QString& random_key);
+    // Constructor for seafile encryption v3
+    CreateRepoRequest(const Account& account,
+                      const QString& name,
+                      const QString& desc,
+                      int enc_version,
+                      const QString& repo_id,
+                      const QString& magic,
+                      const QString& random_key,
+                      const QString& salt);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+signals:
+    void success(const RepoDownloadInfo& info);
+
+private:
+    Q_DISABLE_COPY(CreateRepoRequest)
+};
+
+class CreateSubrepoRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+
+public:
+    explicit CreateSubrepoRequest(const Account& account,
+                                  const QString& name,
+                                  const QString& repoid,
+                                  const QString& path,
+                                  const QString& passwd);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+signals:
+    void success(const QString& sub_repoid);
+
+private:
+    Q_DISABLE_COPY(CreateSubrepoRequest)
+};
+
+class GetUnseenSeahubNotificationsRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+
+public:
+    explicit GetUnseenSeahubNotificationsRequest(const Account& account);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+signals:
+    void success(int count);
+
+private:
+    Q_DISABLE_COPY(GetUnseenSeahubNotificationsRequest)
+};
+
+class GetDefaultRepoRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetDefaultRepoRequest(const Account& account);
+
+signals:
+    void success(bool exists, const QString& repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetDefaultRepoRequest);
+};
+
+class CreateDefaultRepoRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    CreateDefaultRepoRequest(const Account& account);
+
+signals:
+    void success(const QString& repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(CreateDefaultRepoRequest);
+};
+
+class GetStarredFilesRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetStarredFilesRequest(const Account& account);
+
+signals:
+    void success(const std::vector<StarredItem>& starred_files);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetStarredFilesRequest);
+};
+
+// get starred item api v2.1
+class GetStarredFilesRequestV2 : public SeafileApiRequest
+{
+Q_OBJECT
+public:
+    GetStarredFilesRequestV2(const Account& account);
+
+signals:
+    void success(const std::vector<StarredItem>& starred_files);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetStarredFilesRequestV2);
+};
+
+class GetEventsRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetEventsRequest(const Account& account, int start = 0);
+
+signals:
+    void success(const std::vector<SeafEvent>& events, int more_offset);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetEventsRequest);
+};
+
+class GetEventsRequestV2 : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetEventsRequestV2(const Account& account, int page = 1, int perpage = 25, int avatar_size = 36);
+
+signals:
+    void success(const std::vector<SeafEvent>& events);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetEventsRequestV2);
+};
+
+class GetCommitDetailsRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetCommitDetailsRequest(const Account& account,
+                            const QString& repo_id,
+                            const QString& commit_id);
+
+signals:
+    void success(const CommitDetails& result);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetCommitDetailsRequest);
+};
+
+class FetchImageRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    FetchImageRequest(const QString& img_url);
+
+signals:
+    void success(const QImage& avatar);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(FetchImageRequest);
+};
+
+class GetAvatarRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetAvatarRequest(const Account& account,
+                     const QString& email,
+                     qint64 mtime,
+                     int size);
+
+    ~GetAvatarRequest();
+
+    const QString& email() const
+    {
+        return email_;
+    }
+    const Account& account() const
+    {
+        return account_;
+    }
+    qint64 mtime() const
+    {
+        return mtime_;
+    }
+
+signals:
+    void success(const QImage& avatar);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetAvatarRequest);
+
+    FetchImageRequest* fetch_img_req_;
+
+    QString email_;
+
+    Account account_;
+
+    qint64 mtime_;
+};
+
+class SetRepoPasswordRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    SetRepoPasswordRequest(const Account& account,
+                           const QString& repo_id,
+                           const QString& password);
+
+signals:
+    void success();
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(SetRepoPasswordRequest);
+};
+
+class ServerInfoRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    ServerInfoRequest(const Account& account);
+
+signals:
+    void success(const Account& account, const ServerInfo& info);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(ServerInfoRequest);
+    const Account& account_;
+};
+
+class LogoutDeviceRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    LogoutDeviceRequest(const Account& account);
+
+    const Account& account()
+    {
+        return account_;
+    }
+
+signals:
+    void success();
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(LogoutDeviceRequest);
+
+    Account account_;
+};
+
+class SingleBatchRepoTokensRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    SingleBatchRepoTokensRequest(const Account& account, const QStringList& repo_ids);
+
+    const QMap<QString, QString>& repoTokens() const
+    {
+        return repo_tokens_;
+    }
+
+    const QStringList repoIds() const {
+        return repo_ids_;
+    }
+
+signals:
+    void success();
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(SingleBatchRepoTokensRequest);
+
+    QStringList repo_ids_;
+    QMap<QString, QString> repo_tokens_;
+};
+
+// Request repo sync tokens from the server, and break the request into batches
+// if there are too many, to avoid request URI too large.
+class GetRepoTokensRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetRepoTokensRequest(const Account& account, const QStringList& repo_ids, int max_retry, int batch_size=50);
+
+    virtual void send() Q_DECL_OVERRIDE;
+
+    const QMap<QString, QString>& repoTokens() const
+    {
+        return repo_tokens_;
+    }
+
+    int maxRetries() const { return max_retries_; }
+    const QStringList& repoIds() const { return repo_ids_; }
+    const Account& account() const
+    {
+        return account_;
+    }
+
+signals:
+    void success();
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private slots:
+    void batchSuccess();
+
+private:
+    Q_DISABLE_COPY(GetRepoTokensRequest);
+
+    void doNextBatch();
+
+    Account account_;
+    QStringList repo_ids_;
+    QMap<QString, QString> repo_tokens_;
+    int max_retries_;
+
+    // The start position of the next batch
+    int batch_offset_;
+    // How many tokens to ask in a single request
+    int batch_size_;
+
+    QScopedPointer<SingleBatchRepoTokensRequest, QScopedPointerDeleteLater> batch_req_;
+};
+
+class GetLoginTokenRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetLoginTokenRequest(const Account& account, const QString& next_url);
+
+    const Account& account()
+    {
+        return account_;
+    }
+    const QString& nextUrl()
+    {
+        return next_url_;
+    }
+
+signals:
+    void success(const QString& token);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetLoginTokenRequest);
+
+    Account account_;
+    QString next_url_;
+};
+
+struct FileSearchResult {
+    QString repo_id;
+    QString repo_name;
+    QString name;
+    QString oid;
+    qint64 last_modified;
+    QString fullpath;
+    qint64 size;
+    bool is_dir;
+};
+
+Q_DECLARE_METATYPE(FileSearchResult)
+
+class FileSearchRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    FileSearchRequest(const Account& account,
+                      const QString& keyword,
+                      int page = 0,
+                      int per_page = 10,
+                      const QString& repo_id = QString());
+    const QString& keyword() const
+    {
+        return keyword_;
+    }
+
+signals:
+    void success(const std::vector<FileSearchResult>& result,
+                 bool is_loading_more,
+                 bool has_more);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(FileSearchRequest);
+
+    const QString keyword_;
+    const int page_;
+};
+
+class FetchCustomLogoRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    FetchCustomLogoRequest(const QUrl& url);
+
+signals:
+    void success(const QUrl& url);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(FetchCustomLogoRequest);
+};
+
+class FetchAccountInfoRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    FetchAccountInfoRequest(const Account& account);
+
+    const Account& account() const
+    {
+        return account_;
+    }
+
+signals:
+    void success(const AccountInfo& info);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(FetchAccountInfoRequest);
+
+    Account account_;
+};
+
+class PrivateShareRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    enum ShareOperation {
+        ADD_SHARE,
+        UPDATE_SHARE,
+        REMOVE_SHARE,
+    };
+    PrivateShareRequest(const Account& account,
+                        const QString& repo_id,
+                        const QString& path,
+                        const SeafileUser& user,
+                        int group_id,
+                        SharePermission permission,
+                        ShareType share_type,
+                        ShareOperation op);
+
+    ShareOperation shareOperation() const
+    {
+        return share_operation_;
+    }
+
+    int groupId() const
+    {
+        return share_type_ == SHARE_TO_GROUP ? group_id_ : -1;
+    };
+
+    SeafileUser user() const
+    {
+        return share_type_ == SHARE_TO_USER ? user_ : SeafileUser();
+    };
+
+    SharePermission permission() const
+    {
+        return permission_;
+    }
+
+    ShareType shareType() const
+    {
+        return share_type_;
+    }
+
+signals:
+    void success();
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(PrivateShareRequest);
+
+    int group_id_;
+    SeafileUser user_;
+    SharePermission permission_;
+    ShareType share_type_;
+    ShareOperation share_operation_;
+};
+
+class GetPrivateShareItemsRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetPrivateShareItemsRequest(const Account& account,
+                                const QString& repo_id,
+                                const QString& path);
+
+signals:
+    void success(const QList<GroupShareInfo>&, const QList<UserShareInfo>&);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetPrivateShareItemsRequest);
+};
+
+class FetchGroupsAndContactsRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    FetchGroupsAndContactsRequest(const Account& account);
+
+signals:
+    void success(const QList<SeafileGroup>&, const QList<SeafileUser>&);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(FetchGroupsAndContactsRequest);
+};
+
+
+class RemoteWipeReportRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    RemoteWipeReportRequest(const Account& account);
+
+signals:
+    void success();
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(RemoteWipeReportRequest);
+};
+
+class SearchUsersRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    SearchUsersRequest(const Account& account, const QString& pattern);
+
+    QString pattern() const { return pattern_; }
+
+signals:
+    void success(const QList<SeafileUser>& users);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(SearchUsersRequest);
+
+    QString pattern_;
+};
+
+class FetchGroupsRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    FetchGroupsRequest(const Account& account);
+
+signals:
+    void success(const QList<SeafileGroup>&);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(FetchGroupsRequest);
+};
+
+class GetThumbnailRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetThumbnailRequest(const Account& account,
+                        const QString& repo_id,
+                        const QString& path,
+                       const QString& dirent_id,
+                        uint size);
+
+    const Account& account() const
+    {
+        return account_;
+    }
+    const QString& repoId() const
+    {
+        return repo_id_;
+    }
+    const QString& path() const
+    {
+        return path_;
+    }
+    const QString& direntId() const
+    {
+        return dirent_id_;
+    }
+    uint size() const
+    {
+        return size_;
+    }
+signals:
+    void success(const QPixmap& thumbnail);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetThumbnailRequest);
+    Account account_;
+    QString repo_id_;
+    QString path_;
+    QString dirent_id_;
+    uint size_;
+};
+
+class UnshareRepoRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    UnshareRepoRequest(const Account& account,
+                       const QString& repo_id,
+                       const QString& from_user);
+
+    const QString& repoId() { return repo_id_; }
+
+signals:
+    void success();
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(UnshareRepoRequest);
+
+    QString repo_id_;
+};
+
+struct UploadLinkInfo {
+    QString username;
+    QString repo_id;
+    QString ctime;
+    QString token;
+    QString link;
+    QString path;
+};
+
+class CreateFileUploadLinkRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    CreateFileUploadLinkRequest(const Account& account,
+                         const QString& repo_id,
+                         const QString& path,
+                         const QString& password = QString());
+
+signals:
+    void success(const UploadLinkInfo& link_info);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(CreateFileUploadLinkRequest);
+    QString repo_id_;
+    QString path_;
+    QString password_;
+};
+
+class GetUploadFileLinkRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetUploadFileLinkRequest(const QString& link);
+
+signals:
+    void success(const QString& url);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetUploadFileLinkRequest);
+};
+
+#endif // SEAFILE_CLIENT_API_REQUESTS_H
diff --git a/src/api/server-info.h b/src/api/server-info.h
new file mode 100644 (file)
index 0000000..8f634ee
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef SEAFILE_CLIENT_API_SERVER_INFO_H
+#define SEAFILE_CLIENT_API_SERVER_INFO_H
+#include <QString>
+#include <QStringList>
+
+class ServerInfo {
+public:
+  unsigned majorVersion;
+  unsigned minorVersion;
+  unsigned patchVersion;
+  unsigned encryptedLibraryVersion = 2;
+  bool proEdition;
+  bool officePreview;
+  bool fileSearch;
+  bool disableSyncWithAnyFolder;
+  QString customBrand;
+  QString customLogo;
+
+  bool operator== (const ServerInfo &rhs) const {
+      return majorVersion == rhs.majorVersion &&
+          minorVersion == rhs.minorVersion &&
+          patchVersion == rhs.patchVersion &&
+          encryptedLibraryVersion == rhs.encryptedLibraryVersion &&
+          proEdition == rhs.proEdition &&
+          officePreview == rhs.officePreview &&
+          fileSearch == rhs.fileSearch &&
+          disableSyncWithAnyFolder == rhs.disableSyncWithAnyFolder &&
+          customBrand == rhs.customBrand &&
+          customLogo == rhs.customLogo;
+  }
+  bool operator!= (const ServerInfo &rhs) const {
+      return !(*this == rhs);
+  }
+  bool parseVersionFromString(const QString &version) {
+      QStringList versions = version.split('.');
+      if (versions.size() < 3)
+          return false;
+      majorVersion = versions[0].toInt();
+      minorVersion = versions[1].toInt();
+      patchVersion = versions[2].toInt();
+      return true;
+  }
+
+  bool parseEncryptedLibraryVersionFromString(const QString &version) {
+      bool ok;
+      encryptedLibraryVersion = version.toInt(&ok);
+      return ok;
+  }
+
+  void parseFeatureFromStrings(const QStringList& input) {
+      proEdition = false;
+      officePreview = false;
+      fileSearch = false;
+      disableSyncWithAnyFolder = false;
+      Q_FOREACH(const QString& key, input)
+      {
+          parseFeatureFromString(key);
+      }
+  }
+  bool parseFeatureFromString(const QString& key, bool value = true) {
+      if (key == "seafile-pro") {
+          proEdition = value;
+      } else if (key == "office-preview") {
+          officePreview = value;
+      } else if (key == "file-search") {
+          fileSearch = value;
+      } else if (key == "disable-sync-with-any-folder") {
+          disableSyncWithAnyFolder = value;
+      } else {
+          return false;
+      }
+      return true;
+  }
+  QString getVersionString() const {
+      return QString("%1.%2.%3")
+          .arg(QString::number(majorVersion))
+          .arg(QString::number(minorVersion))
+          .arg(QString::number(patchVersion));
+  }
+
+  int getEncryptedLibraryVersion() const {
+      return encryptedLibraryVersion;
+  }
+
+  QStringList getFeatureStrings() const {
+      QStringList result;
+      if (proEdition)
+          result.push_back("seafile-pro");
+      if (officePreview)
+          result.push_back("office-preview");
+      if (fileSearch)
+          result.push_back("file-search");
+      if (disableSyncWithAnyFolder)
+          result.push_back("disable-sync-with-any-folder");
+      return result;
+  }
+};
+
+
+
+#endif // SEAFILE_CLIENT_API_SERVER_INFO_H
diff --git a/src/api/server-repo.cpp b/src/api/server-repo.cpp
new file mode 100644 (file)
index 0000000..adb7272
--- /dev/null
@@ -0,0 +1,76 @@
+#include <vector>
+#include <jansson.h>
+#include <QPixmap>
+
+#include "server-repo.h"
+
+namespace {
+
+QString getStringFromJson(const json_t *json, const char* key)
+{
+    return QString::fromUtf8(json_string_value(json_object_get(json, key)));
+}
+
+} // namespace
+
+
+ServerRepo ServerRepo::fromJSON(const json_t *json, json_error_t */* error */)
+{
+    ServerRepo repo;
+    repo.id = getStringFromJson(json, "id");
+    repo.name = getStringFromJson(json, "name");
+    repo.description = getStringFromJson(json, "desc");
+
+    repo.mtime = json_integer_value(json_object_get(json, "mtime"));
+    repo.size = json_integer_value(json_object_get(json, "size"));
+    repo.root = getStringFromJson(json, "root");
+
+    repo.encrypted = json_is_true(json_object_get(json, "encrypted"));
+
+    repo.type = getStringFromJson(json, "type");
+    repo.permission = getStringFromJson(json, "permission");
+    repo.readonly = (repo.permission == "r") ? true : false;
+
+    repo._virtual = json_is_true(json_object_get(json, "virtual"));
+
+    if (repo.type == "grepo") {
+        repo.owner = getStringFromJson(json, "share_from");
+        repo.group_name = getStringFromJson(json, "owner");
+        repo.group_id = json_integer_value(json_object_get(json, "groupid"));
+    } else {
+        repo.owner = getStringFromJson(json, "owner");
+        repo.group_name = QString();
+        repo.group_id = 0;
+    }
+
+    return repo;
+}
+
+std::vector<ServerRepo> ServerRepo::listFromJSON(const json_t *json, json_error_t *error)
+{
+    std::vector<ServerRepo> repos;
+    for (size_t i = 0; i < json_array_size(json); i++) {
+        ServerRepo repo = fromJSON(json_array_get(json, i), error);
+        repos.push_back(repo);
+    }
+
+    return repos;
+}
+
+QIcon ServerRepo::getIcon() const
+{
+    if (this->isSubfolder()) {
+        return QIcon(":/images/main-panel/folder.png");
+    } else if (encrypted) {
+        return QIcon(":/images/main-panel/library-encrypted.png");
+    } else if (readonly) {
+        return QIcon(":/images/main-panel/library-readonly.png");
+    } else {
+        return QIcon(":/images/main-panel/library-normal.png");
+    }
+}
+
+QPixmap ServerRepo::getPixmap(int size) const
+{
+    return getIcon().pixmap(size);
+}
diff --git a/src/api/server-repo.h b/src/api/server-repo.h
new file mode 100644 (file)
index 0000000..9e41d5d
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef SEAFILE_CLIENT_SERVER_REPO_H
+#define SEAFILE_CLIENT_SERVER_REPO_H
+
+#include <vector>
+#include <QString>
+#include <QMetaType>
+#include <QIcon>
+#include <QPixmap>
+#include <jansson.h>
+
+/**
+ * Repo information from seahub api
+ */
+class ServerRepo {
+public:
+    ServerRepo() : encrypted(false), readonly(false), _virtual(false), group_id (0) {};
+
+    QString id;
+    QString name;
+    QString description;
+
+    qint64 mtime;
+    qint64  size;
+    QString root;
+
+    bool encrypted;
+    bool readonly;
+
+    // "virtual" is a reserved word in C++
+    bool _virtual;
+
+    // subfolder attributes
+    QString parent_repo_id;
+    QString parent_path;
+
+    QString type;
+    QString owner;
+    QString permission;
+    QString group_name;
+    int group_id;
+
+    bool isValid() const { return !id.isEmpty(); }
+
+    bool isPersonalRepo() const { return type == "repo"; }
+    bool isSharedRepo() const { return type == "srepo"; }
+    bool isGroupRepo() const { return type == "grepo"; }
+    bool isOrgRepo() const { return isGroupRepo() and group_id == 0; }
+
+    bool isVirtual() const { return _virtual; }
+    bool isSubfolder() const { return !parent_repo_id.isEmpty() && !parent_path.isEmpty(); }
+
+    QIcon getIcon() const;
+    QPixmap getPixmap(int size = 24) const;
+
+    static ServerRepo fromJSON(const json_t*, json_error_t *error);
+    static std::vector<ServerRepo> listFromJSON(const json_t*, json_error_t *json);
+};
+
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(ServerRepo)
+
+
+#endif // SEAFILE_CLIENT_SERVER_REPO_H
diff --git a/src/api/starred-file.cpp b/src/api/starred-file.cpp
new file mode 100644 (file)
index 0000000..8ffe785
--- /dev/null
@@ -0,0 +1,95 @@
+#include <jansson.h>
+
+#include <vector>
+#include <QFileInfo>
+#include <QDateTime>
+
+#include "starred-file.h"
+
+namespace {
+
+QString getStringFromJson(const json_t *json, const char* key)
+{
+    return QString::fromUtf8(json_string_value(json_object_get(json, key)));
+}
+
+bool getBoolFromJson(const json_t *json, const char* key)
+{
+    return json_is_true(json_object_get(json, key));
+}
+
+} // namespace
+
+
+StarredItem StarredItem::fromJSON(const json_t *json, json_error_t */* error */)
+{
+    StarredItem file;
+    file.repo_id = getStringFromJson(json, "repo_id");
+    if (file.repo_id.isEmpty()) {
+        file.repo_id = getStringFromJson(json, "repo");
+    }
+    file.repo_name = getStringFromJson(json, "repo_name");
+    file.path = getStringFromJson(json, "path");
+
+    file.mtime = json_integer_value(json_object_get(json, "mtime"));
+    file.size = json_integer_value(json_object_get(json, "size"));
+
+    return file;
+}
+
+StarredItem StarredItem::fromJSONV2(const json_t *json, json_error_t */* error */)
+{
+    StarredItem file;
+    file.repo_id = getStringFromJson(json, "repo_id");
+
+    file.repo_name = getStringFromJson(json, "repo_name");
+    file.path = getStringFromJson(json, "path");
+    bool is_dir = getBoolFromJson(json, "is_dir");
+    file.type = StarredItem::FILE;
+    if (is_dir) {
+        if (file.path == "/") {
+            file.type = StarredItem::REPO;
+        } else {
+            file.type = StarredItem::DIR;
+        }
+    }
+
+    file.obj_name = getStringFromJson(json, "obj_name");
+
+    QString date_time = getStringFromJson(json, "mtime");
+    file.mtime = QDateTime::fromString(date_time, Qt::ISODate).toMSecsSinceEpoch() / 1000;
+
+    file.from_new_api = true;
+
+    return file;
+}
+
+std::vector<StarredItem> StarredItem::listFromJSON(const json_t *json, json_error_t *error, bool is_use_new_json_parser)
+{
+    std::vector<StarredItem> files;
+    for (size_t i = 0; i < json_array_size(json); i++) {
+        StarredItem file;
+        if (is_use_new_json_parser) {
+            file = fromJSONV2(json_array_get(json, i), error);
+        } else {
+            file = fromJSON(json_array_get(json, i), error);
+        }
+        files.push_back(file);
+    }
+
+    return files;
+}
+
+const QString StarredItem::name() const
+{
+    if (from_new_api) {
+        return obj_name;
+    } else {
+        return QFileInfo(path).fileName();
+    }
+}
+
+bool StarredItem::isFile() const
+{
+    return type == FILE;
+}
diff --git a/src/api/starred-file.h b/src/api/starred-file.h
new file mode 100644 (file)
index 0000000..89a7920
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef SEAFILE_CLIENT_STARRED_FILE_H
+#define SEAFILE_CLIENT_STARRED_FILE_H
+
+#include <vector>
+#include <QString>
+#include <QMetaType>
+#include <jansson.h>
+
+class StarredItem {
+public:
+    QString repo_id;
+    QString repo_name;
+    QString path;
+    qint64 size;
+    qint64 mtime;
+    QString obj_name;
+
+    enum StarredItemType {
+        FILE = 0,
+        DIR,
+        REPO
+    } type;
+
+    bool from_new_api;
+
+    static StarredItem fromJSON(const json_t*, json_error_t *error);
+    static StarredItem fromJSONV2(const json_t*, json_error_t *error);
+    static std::vector<StarredItem> listFromJSON(const json_t*, json_error_t *json, bool is_use_new_json_parser = false);
+
+    const QString name() const;
+    bool isFile() const;
+};
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(StarredItem)
+
+#endif // SEAFILE_CLIENT_STARRED_FILE_H
diff --git a/src/application.cpp b/src/application.cpp
new file mode 100644 (file)
index 0000000..3b9a5d1
--- /dev/null
@@ -0,0 +1,54 @@
+#include "application.h"
+
+#include <objc/objc.h>
+#include <objc/message.h>
+
+#include <QFileOpenEvent>
+
+#include "open-local-helper.h"
+#include "ui/main-window.h"
+#include "seafile-applet.h"
+static bool dockClickHandler(id self,SEL _cmd,...)
+{
+    Q_UNUSED(self)
+    Q_UNUSED(_cmd)
+    if (seafApplet) {
+        MainWindow *main_win = seafApplet->mainWindow();
+        if (main_win)
+            main_win->showWindow();
+    }
+    return true;
+}
+
+Application::Application (int &argc, char **argv):QApplication(argc, argv)
+{
+    objc_object* cls = (objc_object *)objc_getClass("NSApplication");
+    SEL sharedApplication = sel_registerName("sharedApplication");
+    objc_object* appInst = objc_msgSend(cls,sharedApplication);
+
+    if(appInst != NULL)
+    {
+        objc_object* delegate = objc_msgSend(appInst, sel_registerName("delegate"));
+        objc_object* delClass = objc_msgSend(delegate,  sel_registerName("class"));
+        class_addMethod((Class)delClass, sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:"), (IMP)dockClickHandler, "B@:");
+    }
+}
+
+bool Application::event(QEvent *e)
+{
+    if (e->type() == QEvent::FileOpen)
+    {
+        QFileOpenEvent *event = static_cast<QFileOpenEvent *>(e);
+        // this event has native mac handler callee
+        if(event && event->url().scheme() == "seafile")
+        {
+            qWarning("[FileOpen] trying to open %s\n", event->url().toEncoded().data());
+            if (!seafApplet->started())
+                OpenLocalHelper::instance()->setUrl(event->url().toEncoded().data());
+            else
+                OpenLocalHelper::instance()->openLocalFile(event->url());
+            return true;
+        }
+    }
+    return QApplication::event(e);
+}
diff --git a/src/application.h b/src/application.h
new file mode 100644 (file)
index 0000000..f846960
--- /dev/null
@@ -0,0 +1,15 @@
+/**
+ * Show thr main window when the dock icon is clicked
+ */
+#include <QApplication>
+
+#include "ui/main-window.h"
+class Application : public QApplication {
+    Q_OBJECT
+
+public:
+
+    Application (int& argc, char **argv);
+    bool event(QEvent * e);
+    virtual ~Application() {};
+};
diff --git a/src/auto-login-service.cpp b/src/auto-login-service.cpp
new file mode 100644 (file)
index 0000000..ae565b7
--- /dev/null
@@ -0,0 +1,77 @@
+#include <QDesktopServices>
+#include <QHash>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "utils/utils.h"
+
+#include "auto-login-service.h"
+
+namespace {
+
+} // namespace
+
+SINGLETON_IMPL(AutoLoginService)
+
+AutoLoginService::AutoLoginService(QObject *parent)
+    : QObject(parent)
+{
+}
+
+void AutoLoginService::startAutoLogin(const QString& next_url)
+{
+    const Account account = seafApplet->accountManager()->currentAccount();
+    QUrl absolute_url = QUrl(next_url).isRelative()
+                            ? account.getAbsoluteUrl(next_url)
+                            : next_url;
+    if (!account.isValid() || !account.isAtLeastVersion(4, 2, 0)) {
+        QDesktopServices::openUrl(absolute_url);
+        return;
+    }
+
+    QString next = absolute_url.path();
+    if (absolute_url.hasQuery()) {
+        next += "?" + absolute_url.query();
+    }
+    if (!absolute_url.fragment().isEmpty()) {
+        next += "#" + absolute_url.fragment();
+    }
+    GetLoginTokenRequest *req = new GetLoginTokenRequest(account, next);
+
+    connect(req, SIGNAL(success(const QString&)),
+            this, SLOT(onGetLoginTokenSuccess(const QString&)));
+
+    connect(req, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetLoginTokenFailed(const ApiError&)));
+
+    req->send();
+}
+
+void AutoLoginService::onGetLoginTokenSuccess(const QString& token)
+{
+    GetLoginTokenRequest *req = (GetLoginTokenRequest *)(sender());
+    // printf("login token is %s\n", token.toUtf8().data());
+
+    QUrl url = req->account().getAbsoluteUrl("/client-login/");
+    QString next_url = req->nextUrl();
+
+    QHash<QString, QString> params;
+    params.insert("token", token);
+    params.insert("next", req->nextUrl());
+    url = includeQueryParams(url, params);
+
+    QDesktopServices::openUrl(url);
+    req->deleteLater();
+}
+
+void AutoLoginService::onGetLoginTokenFailed(const ApiError& error)
+{
+    GetLoginTokenRequest *req = (GetLoginTokenRequest *)(sender());
+    qWarning("get login token failed: %s\n", error.toString().toUtf8().data());
+    // server doesn't support client directly login, or other errors happened.
+    // We open the server url directly in this case;
+    QDesktopServices::openUrl(req->account().getAbsoluteUrl(req->nextUrl()));
+    req->deleteLater();
+}
diff --git a/src/auto-login-service.h b/src/auto-login-service.h
new file mode 100644 (file)
index 0000000..6502e7a
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef SEAFILE_CLIENT_AUTO_LOGIN_SERVICE_H_
+#define SEAFILE_CLIENT_AUTO_LOGIN_SERVICE_H_
+
+#include <QObject>
+#include <QString>
+
+#include "utils/singleton.h"
+
+class ApiError;
+
+class AutoLoginService : public QObject {
+    SINGLETON_DEFINE(AutoLoginService)
+    Q_OBJECT
+public:
+    AutoLoginService(QObject *parent=0);
+    // Get a auto login token from server, and then open the "next_url" after login
+
+public slots:
+    void startAutoLogin(const QString& next_url);
+
+private slots:
+    void onGetLoginTokenSuccess(const QString& token);
+    void onGetLoginTokenFailed(const ApiError& error);
+};
+
+#endif  // SEAFILE_CLIENT_AUTO_LOGIN_SERVICE_H_
diff --git a/src/auto-update-service.cpp b/src/auto-update-service.cpp
new file mode 100644 (file)
index 0000000..5bc987b
--- /dev/null
@@ -0,0 +1,175 @@
+#include <QSettings>
+
+#ifdef Q_OS_WIN32
+    #include <winsparkle.h>
+#else
+    #include "mac-sparkle-support.h"
+#endif
+
+#include "i18n.h"
+#include "api/requests.h"
+#include "seafile-applet.h"
+#include "utils/utils.h"
+
+#include "auto-update-service.h"
+
+SINGLETON_IMPL(AutoUpdateService)
+
+namespace
+{
+#ifdef Q_OS_WIN32
+    const char *kSparkleAppcastURI = "https://www.seafile.com/api/client-updates/seafile-client-windows/appcast.xml";
+    const char *kSparkleAppcastURIForCN = "https://www.seafile.com/api/client-updates/seafile-client-windows-cn/appcast.xml";
+    const char *kWinSparkleRegistryPath = "SOFTWARE\\Seafile\\Seafile Client\\WinSparkle";
+#else
+    const char *kSparkleAppcastURI = "https://www.seafile.com/api/client-updates/seafile-client-mac/appcast.xml";
+    const char *kSparkleAppcastURIForCN = "https://www.seafile.com/api/client-updates/seafile-client-mac-cn/appcast.xml";
+#endif
+    const char *kSparkleAlreadyEnableUpdateByDefault = "SparkleAlreadyEnableUpdateByDefault";
+
+QString getAppcastURI() {
+    QString url_from_env = qgetenv("SEAFILE_CLIENT_APPCAST_URI");
+    if (!url_from_env.isEmpty()) {
+        qWarning(
+            "winsparkle: using app cast url from SEAFILE_CLIENT_APPCAST_URI: "
+            "%s",
+            url_from_env.toUtf8().data());
+        return url_from_env;
+    }
+    return I18NHelper::getInstance()->isChinese() ? kSparkleAppcastURIForCN : kSparkleAppcastURI;
+}
+
+} // namespace
+
+// Virtual base class for windows/mac
+class AutoUpdateAdapter {
+public:
+    virtual void prepare() = 0;
+    virtual void start() = 0;
+    virtual void stop() = 0;
+    virtual void checkNow() = 0;
+    virtual bool autoUpdateEnabled() = 0;
+    virtual void setAutoUpdateEnabled(bool enabled) = 0;
+};
+
+#ifdef Q_OS_WIN32
+class WindowsAutoUpdateAdapter: public AutoUpdateAdapter {
+public:
+    void prepare() {
+        // Note that @param path is relative to HKCU/HKLM root
+        // and the root is not part of it. For example:
+        // @code
+        //     win_sparkle_set_registry_path("Software\\My App\\Updates");
+        // @endcode
+        win_sparkle_set_registry_path(kWinSparkleRegistryPath);
+        win_sparkle_set_appcast_url(getAppcastURI().toUtf8().data());
+        win_sparkle_set_app_details(
+            L"Seafile",
+            L"Seafile Client",
+            QString(STRINGIZE(SEAFILE_CLIENT_VERSION)).toStdWString().c_str());
+    }
+
+    void start() {
+        win_sparkle_init();
+    }
+
+    void stop() {
+        win_sparkle_cleanup();
+    }
+
+    void checkNow() {
+        win_sparkle_check_update_with_ui();
+    }
+
+    bool autoUpdateEnabled() {
+        // qWarning() << "autoUpdateEnabled =" << win_sparkle_get_automatic_check_for_updates();
+        return win_sparkle_get_automatic_check_for_updates();
+    }
+
+    void setAutoUpdateEnabled(bool enabled) {
+        win_sparkle_set_automatic_check_for_updates(enabled ? 1 : 0);
+    }
+};
+#elif defined(Q_OS_MAC)
+class MacAutoUpdateAdapter: public AutoUpdateAdapter {
+public:
+    void prepare() {
+        SparkleHelper::setFeedURL(getAppcastURI().toUtf8().data());
+    }
+
+    void start() {
+    }
+
+    void stop() {
+    }
+
+    void checkNow() {
+        SparkleHelper::checkForUpdate();
+    }
+
+    bool autoUpdateEnabled() {
+        return SparkleHelper::autoUpdateEnabled();
+    }
+
+    void setAutoUpdateEnabled(bool enabled) {
+        SparkleHelper::setAutoUpdateEnabled(enabled);
+    }
+};
+#endif
+
+
+AutoUpdateService::AutoUpdateService(QObject *parent) : QObject(parent)
+{
+#ifdef Q_OS_WIN32
+    adapter_ = new WindowsAutoUpdateAdapter;
+#else
+    adapter_ = new MacAutoUpdateAdapter;
+#endif
+}
+
+void AutoUpdateService::start()
+{
+    adapter_->prepare();
+    enableUpdateByDefault();
+    adapter_->start();
+}
+
+void AutoUpdateService::enableUpdateByDefault() {
+    // Enable auto update check by default.
+    QSettings settings;
+    settings.beginGroup("Misc");
+    bool already_enable_update_by_default = settings.value(kSparkleAlreadyEnableUpdateByDefault, false).toBool();
+
+    if (!already_enable_update_by_default) {
+        settings.setValue(kSparkleAlreadyEnableUpdateByDefault, true);
+        setAutoUpdateEnabled(true);
+    }
+
+    settings.endGroup();
+}
+
+void AutoUpdateService::stop()
+{
+    adapter_->stop();
+}
+
+
+void AutoUpdateService::checkUpdate()
+{
+    adapter_->checkNow();
+}
+
+
+bool AutoUpdateService::shouldSupportAutoUpdate() const {
+    // qWarning() << "shouldSupportAutoUpdate =" << (QString(getBrand()) == "Seafile");
+    return QString(getBrand()) == "Seafile";
+}
+
+bool AutoUpdateService::autoUpdateEnabled() const {
+    return adapter_->autoUpdateEnabled();
+}
+
+void AutoUpdateService::setAutoUpdateEnabled(bool enabled) {
+    // qWarning() << "setAutoUpdateEnabled:" << enabled;
+    adapter_->setAutoUpdateEnabled(enabled);
+}
diff --git a/src/auto-update-service.h b/src/auto-update-service.h
new file mode 100644 (file)
index 0000000..a4cc27f
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SEAFILE_CLIENT_AUTO_UPDATE_SERVICE_H
+#define SEAFILE_CLIENT_AUTO_UPDATE_SERVICE_H
+
+#include <QObject>
+#include <QString>
+
+#include "utils/singleton.h"
+
+class AutoUpdateAdapter;
+
+// Auto update seafile client program. Only used on windows/mac.
+class AutoUpdateService : public QObject
+{
+    SINGLETON_DEFINE(AutoUpdateService)
+    Q_OBJECT
+
+public:
+    AutoUpdateService(QObject *parent = 0);
+
+    bool shouldSupportAutoUpdate() const;
+
+    void setRequestParams();
+    bool autoUpdateEnabled() const;
+    void setAutoUpdateEnabled(bool enabled);
+
+    void start();
+    void stop();
+
+    void checkUpdate();
+
+private:
+    void enableUpdateByDefault();
+    QString getAppcastURI();
+    AutoUpdateAdapter *adapter_;
+};
+
+#endif // SEAFILE_CLIENT_AUTO_UPDATE_SERVICE_H
diff --git a/src/avatar-service.cpp b/src/avatar-service.cpp
new file mode 100644 (file)
index 0000000..fcd5af8
--- /dev/null
@@ -0,0 +1,394 @@
+#include <QDir>
+#include <QImage>
+#include <QQueue>
+#include <QHash>
+#include <QTimer>
+#include <QDateTime>
+
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "account-mgr.h"
+#include "api/requests.h"
+#include "utils/paint-utils.h"
+#include "utils/utils.h"
+
+#include <sqlite3.h>
+#include "avatar-service.h"
+
+namespace {
+
+const int kCheckPendingInterval = 1000; // 1s
+const char *kAvatarsDirName = "avatars";
+const qint64 kExpireTimeIntevalMsec = 300 * 1000; // 5min
+
+bool loadTimeStampCB(sqlite3_stmt *stmt, void* data)
+{
+    qint64* mtime = reinterpret_cast<qint64*>(data);
+
+    *mtime = sqlite3_column_int64(stmt, 0);
+
+    return true;
+}
+
+} // namespace
+
+const int AvatarService::kAvatarSize = 40;
+const int kAvatarSizeFromServer = 80;
+
+struct PendingRequestInfo {
+    int last_wait;
+    int time_to_wait;
+
+    void backoff() {
+        last_wait = qMax(last_wait, 1) * 2;
+        time_to_wait = last_wait;
+    }
+
+    bool isReady() {
+        return time_to_wait == 0;
+    }
+
+    void tick() {
+        time_to_wait = qMax(0, time_to_wait - 1);
+    }
+};
+
+class PendingAvatarRequestQueue
+{
+public:
+    PendingAvatarRequestQueue() {};
+
+    void enqueue(const QString& email) {
+        if (q_.contains(email)) {
+            return;
+        }
+        // if we have set an expire time, and we haven't reached it yet
+        if (expire_time_.contains(email) &&
+            QDateTime::currentMSecsSinceEpoch() <= expire_time_[email]) {
+            return;
+        }
+        // update expire time
+        expire_time_[email] = QDateTime::currentMSecsSinceEpoch() + kExpireTimeIntevalMsec;
+
+        q_.enqueue(email);
+    }
+
+    void enqueueAndBackoff(const QString& email) {
+        PendingRequestInfo& info = wait_[email];
+        info.backoff();
+
+        enqueue(email);
+    }
+
+    void clearWait(const QString& email) {
+        wait_.remove(email);
+    }
+
+    void tick() {
+        QListIterator<QString> iter(q_);
+
+        while (iter.hasNext()) {
+            QString email = iter.next();
+            if (wait_.contains(email)) {
+                PendingRequestInfo& info = wait_[email];
+                info.tick();
+            }
+        }
+    }
+
+    QString dequeue() {
+        int i = 0, n = q_.size();
+        while (i++ < n) {
+            if (q_.isEmpty()) {
+                return QString();
+            }
+
+            QString email = q_.dequeue();
+
+            PendingRequestInfo info = wait_.value(email);
+            if (info.isReady()) {
+                return email;
+            } else {
+                q_.enqueue(email);
+            }
+        }
+
+        return QString();
+    }
+
+    void reset() {
+        q_.clear();
+        wait_.clear();
+        expire_time_.clear();
+    }
+
+private:
+    QQueue<QString> q_;
+
+    QHash<QString, PendingRequestInfo> wait_;
+    QHash<QString, qint64> expire_time_;
+};
+
+AvatarService* AvatarService::singleton_;
+
+AvatarService* AvatarService::instance()
+{
+    if (singleton_ == NULL) {
+        static AvatarService instance;
+        singleton_ = &instance;
+    }
+
+    return singleton_;
+}
+
+
+AvatarService::AvatarService(QObject *parent)
+    : QObject(parent), get_avatar_req_(NULL)
+{
+    queue_ = new PendingAvatarRequestQueue;
+
+    timer_ = new QTimer(this);
+
+    connect(timer_, SIGNAL(timeout()), this, SLOT(checkPendingRequests()));
+
+    connect(seafApplet->accountManager(), SIGNAL(accountsChanged()),
+            this, SLOT(onAccountChanged()));
+}
+
+void AvatarService::start()
+{
+    QDir seafile_dir(seafApplet->configurator()->seafileDir());
+
+    if (!seafile_dir.mkpath(kAvatarsDirName)) {
+        qWarning("Failed to create avatars folder");
+        QString err_msg = tr("Failed to create avatars folder");
+        seafApplet->errorAndExit(err_msg);
+    }
+
+    avatars_dir_ = seafile_dir.filePath(kAvatarsDirName);
+
+    do {
+        const char *errmsg;
+        QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("accounts.db");
+        if (sqlite3_open (db_path.toUtf8().data(), &autoupdate_db_)) {
+            errmsg = sqlite3_errmsg (autoupdate_db_);
+            qWarning("failed to avatar autoupdate database %s: %s",
+                    db_path.toUtf8().data(), errmsg ? errmsg : "no error given");
+
+            sqlite3_close(autoupdate_db_);
+            autoupdate_db_ = NULL;
+            break;
+        }
+
+        // enabling foreign keys, it must be done manually from each connection
+        // and this feature is only supported from sqlite 3.6.19
+        const char *sql = "PRAGMA foreign_keys=ON;";
+        if (sqlite_query_exec (autoupdate_db_, sql) < 0) {
+            qWarning("sqlite version is too low to support foreign key feature\n");
+            qWarning("feature avatar autoupdate is disabled\n");
+            sqlite3_close(autoupdate_db_);
+            autoupdate_db_ = NULL;
+            break;
+        }
+
+        // create Avatar table
+        sql = "CREATE TABLE IF NOT EXISTS Avatar ("
+            "filename TEXT PRIMARY KEY, timestamp BIGINT, "
+            "url VARCHAR(24), username VARCHAR(15), "
+            "FOREIGN KEY(url, username) REFERENCES Accounts(url, username) "
+            "ON DELETE CASCADE ON UPDATE CASCADE )";
+        if (sqlite_query_exec (autoupdate_db_, sql) < 0) {
+            qWarning("failed to create avatar table\n");
+            sqlite3_close(autoupdate_db_);
+            autoupdate_db_ = NULL;
+        }
+    } while (0);
+
+    timer_->start(kCheckPendingInterval);
+}
+
+// fist check in-memory-cache, then check saved image on disk
+QImage AvatarService::loadAvatarFromLocal(const QString& email)
+{
+    if (cache_.contains(email)) {
+        return cache_.value(email);
+    }
+
+    QImage ret;
+    if (avatarFileExists(email)) {
+        ret = QImage(getAvatarFilePath(email));
+        cache_[email] = ret;
+    }
+
+    return ret;
+}
+
+QString AvatarService::avatarPathForEmail(const Account& account, const QString& email)
+{
+    return QDir(avatars_dir_)
+        .filePath(::md5(account.serverUrl.host() + email + "/" +
+                        QString::number(kAvatarSizeFromServer)));
+}
+
+void AvatarService::fetchImageFromServer(const QString& email)
+{
+    if (get_avatar_req_) {
+        if (email == get_avatar_req_->email()) {
+            return;
+        }
+        queue_->enqueue(email);
+        return;
+    }
+
+    if (!seafApplet->accountManager()->hasAccount())
+        return;
+    const Account& account = seafApplet->accountManager()->accounts().front();
+    // Why we initialize mtime to -1 instead of 0? Because sometimes
+    // the mtime returned by the server is 0, so we must initialize it
+    // to -1 as a special value to indicate there is no local cache
+    // for this avatar yet.
+    qint64 mtime = -1;
+
+    if (autoupdate_db_) {
+        char *zql = sqlite3_mprintf("SELECT timestamp FROM Avatar "
+                                    "WHERE filename = %Q",
+                                    avatarPathForEmail(account, email).toUtf8().data());
+        sqlite_foreach_selected_row(autoupdate_db_, zql, loadTimeStampCB, &mtime);
+        sqlite3_free(zql);
+    }
+
+    get_avatar_req_ = new GetAvatarRequest(account, email, mtime, kAvatarSizeFromServer);
+
+    connect(get_avatar_req_, SIGNAL(success(const QImage&)),
+            this, SLOT(onGetAvatarSuccess(const QImage&)));
+    connect(get_avatar_req_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetAvatarFailed(const ApiError&)));
+
+    get_avatar_req_->send();
+}
+
+void AvatarService::onGetAvatarSuccess(const QImage& img)
+{
+    if (!get_avatar_req_) {
+        return;
+    }
+
+    const QString email = get_avatar_req_->email();
+
+    // if no change? early return
+    if (img.isNull()) {
+        get_avatar_req_->deleteLater();
+        get_avatar_req_ = NULL;
+
+        queue_->clearWait(email);
+        return;
+    }
+
+    image_ = img;
+
+    cache_[email] = img;
+
+    // save image to avatars/ folder
+    QString path = avatarPathForEmail(get_avatar_req_->account(), email);
+    if (!img.save(path, "PNG")) {
+        qWarning("Unable to save new avatar file %s", path.toUtf8().data());
+    }
+
+    // update cache db
+    if (autoupdate_db_) {
+        QString mtime = QString::number(get_avatar_req_->mtime());
+        char *zql = sqlite3_mprintf(
+            "REPLACE INTO Avatar(filename, timestamp, url, username) "
+            "VALUES (%Q, %Q, %Q, %Q)",
+            path.toUtf8().data(),
+            mtime.toUtf8().data(),
+            get_avatar_req_->account().serverUrl.toEncoded().data(),
+            get_avatar_req_->account().username.toUtf8().data());
+        sqlite_query_exec(autoupdate_db_, zql);
+        sqlite3_free(zql);
+    }
+
+    emit avatarUpdated(email, img);
+
+    get_avatar_req_->deleteLater();
+    get_avatar_req_ = NULL;
+
+    queue_->clearWait(email);
+}
+
+void AvatarService::onGetAvatarFailed(const ApiError& error)
+{
+    if (!get_avatar_req_) {
+        return;
+    }
+    const QString email = get_avatar_req_->email();
+    get_avatar_req_->deleteLater();
+    get_avatar_req_ = NULL;
+
+    queue_->enqueueAndBackoff(email);
+}
+
+QImage AvatarService::getAvatar(const QString& email)
+{
+    QImage img = loadAvatarFromLocal(email);
+
+    // TODO: check the timestamp of the cached avatar and update it if too old,
+    // e.g. cached more than one hour ago. We use timestamps when asking the
+    // server for avatars so updating avatars should be a light weight
+    // operation.
+
+    // update all avatars if feature autoupdate enabled or img is null
+    if (autoupdate_db_ || img.isNull()) {
+        if (!get_avatar_req_ || get_avatar_req_->email() != email) {
+            queue_->enqueue(email);
+        }
+    }
+    if (img.isNull()) {
+        return QImage(":/images/account.png");
+    } else {
+        return img;
+    }
+}
+
+QString AvatarService::getAvatarFilePath(const QString& email)
+{
+    const Account& account = seafApplet->accountManager()->accounts().front();
+    return avatarPathForEmail(account, email);
+}
+
+bool AvatarService::avatarFileExists(const QString& email)
+{
+    QString path = getAvatarFilePath(email);
+    bool ret = QFileInfo(path).exists();
+
+    if (!ret) {
+        char *zql = sqlite3_mprintf("DELETE FROM Avatar WHERE filename = %Q", path.toUtf8().data());
+        sqlite_query_exec (autoupdate_db_, zql);
+        sqlite3_free(zql);
+    }
+    return ret;
+}
+
+void AvatarService::checkPendingRequests()
+{
+    queue_->tick();
+
+    if (get_avatar_req_ != NULL) {
+        return;
+    }
+
+    QString email = queue_->dequeue();
+    if (!email.isEmpty()) {
+        fetchImageFromServer(email);
+    }
+}
+
+void AvatarService::onAccountChanged()
+{
+    queue_->reset();
+    if (get_avatar_req_) {
+        get_avatar_req_->deleteLater();
+        get_avatar_req_ = NULL;
+    }
+    cache_.clear();
+}
diff --git a/src/avatar-service.h b/src/avatar-service.h
new file mode 100644 (file)
index 0000000..3906436
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef SEAFILE_CLIENT_AVATAR_SERVICE_H
+#define SEAFILE_CLIENT_AVATAR_SERVICE_H
+
+#include <vector>
+#include <QObject>
+#include <QImage>
+#include <QHash>
+#include <QString>
+
+class QImage;
+class QTimer;
+
+class Account;
+class ApiError;
+class GetAvatarRequest;
+class PendingAvatarRequestQueue;
+
+struct sqlite3;
+
+class AvatarService : public QObject
+{
+    Q_OBJECT
+public:
+    static AvatarService* instance();
+
+    void start();
+
+    QImage getAvatar(const QString& email);
+
+    static const int kAvatarSize;
+
+signals:
+    void avatarUpdated(const QString& email, const QImage& avatar);
+
+private slots:
+    void onGetAvatarSuccess(const QImage& img);
+    void onGetAvatarFailed(const ApiError& error);
+    void checkPendingRequests();
+    void onAccountChanged();
+
+private:
+    Q_DISABLE_COPY(AvatarService)
+
+    AvatarService(QObject *parent=0);
+
+    static AvatarService *singleton_;
+
+    QImage loadAvatarFromLocal(const QString& email);
+    void fetchImageFromServer(const QString& email);
+    QString avatarPathForEmail(const Account& account, const QString& email);
+    QString getAvatarFilePath(const QString& email);
+    bool avatarFileExists(const QString& email);
+
+    GetAvatarRequest *get_avatar_req_;
+
+    QString avatars_dir_;
+
+    QImage image_;
+
+    QHash<QString, QImage> cache_;
+
+    PendingAvatarRequestQueue *queue_;
+
+    QTimer *timer_;
+
+    struct sqlite3 *autoupdate_db_;
+};
+
+
+#endif // SEAFILE_CLIENT_AVATAR_SERVICE_H
diff --git a/src/certs-mgr.cpp b/src/certs-mgr.cpp
new file mode 100644 (file)
index 0000000..a77c8ad
--- /dev/null
@@ -0,0 +1,132 @@
+#include <sqlite3.h>
+#include <glib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <algorithm>
+
+#include <QUrl>
+#include <QObject>
+
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "utils/utils.h"
+
+#include "certs-mgr.h"
+
+namespace {
+
+QString
+certToBase64(const QSslCertificate& cert)
+{
+    QByteArray bytes = cert.toPem();
+    return bytes.toBase64();
+}
+
+QSslCertificate
+certFromBase64(const char *data)
+{
+    QSslCertificate cert;
+    if (!data) {
+        return cert;
+    }
+
+    QByteArray bytes = QByteArray::fromBase64(data);
+
+    cert = QSslCertificate(bytes);
+
+    return cert;
+}
+
+// Remove path and query params from url before converting to string
+QString urlToString(const QUrl& url)
+{
+    QUrl u;
+
+    u.setScheme(url.scheme());
+    u.setHost(url.host());
+    u.setPort(url.port());
+
+    return u.toString();
+}
+
+} // namespace
+
+CertsManager::CertsManager()
+{
+    db = NULL;
+}
+
+CertsManager::~CertsManager()
+{
+    if (db)
+        sqlite3_close(db);
+}
+
+int
+CertsManager::start()
+{
+    const char *errmsg;
+    const char *sql;
+
+    QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("certs.db");
+    if (sqlite3_open (toCStr(db_path), &db)) {
+        errmsg = sqlite3_errmsg (db);
+        qWarning("failed to open certs database %s: %s",
+               toCStr(db_path), errmsg ? errmsg : "no error given");
+
+        seafApplet->errorAndExit(QObject::tr("failed to open certs database"));
+        return -1;
+    }
+
+    sql = "CREATE TABLE IF NOT EXISTS Certs ("
+        "url VARCHAR(255) PRIMARY KEY, "
+        "cert TEXT"
+        ")";
+    sqlite_query_exec (db, sql);
+
+    loadCertificates();
+    return 0;
+}
+
+bool CertsManager::loadCertificatesCB(sqlite3_stmt *stmt, void *data)
+{
+    CertsManager *mgr = (CertsManager *)data;
+    const char *url = (const char *)sqlite3_column_text (stmt, 0);
+    const char *base64 = (const char *)sqlite3_column_text(stmt, 1);
+
+    QSslCertificate cert = certFromBase64(base64);
+    if (!cert.isNull()) {
+        mgr->certs_[url] = cert;
+    }
+
+    return true;
+}
+
+void CertsManager::loadCertificates()
+{
+    const char *sql = "SELECT url, cert FROM Certs";
+    sqlite_foreach_selected_row (db, sql, loadCertificatesCB, this);
+}
+
+void
+CertsManager::saveCertificate(const QUrl& url, const QSslCertificate& cert)
+{
+    QString key = urlToString(url);
+    certs_[key] = cert;
+
+    QString sql = "REPLACE INTO Certs VALUES ('%1', '%2')";
+    sql = sql.arg(key).arg(certToBase64(cert));
+    sqlite_query_exec (db, toCStr(sql));
+}
+
+QSslCertificate
+CertsManager::getCertificate(const QUrl& url)
+{
+    QString key = urlToString(url);
+
+    if (certs_.contains(key)) {
+        return certs_[key];
+    }
+    QSslCertificate cert;
+    return cert;
+}
diff --git a/src/certs-mgr.h b/src/certs-mgr.h
new file mode 100644 (file)
index 0000000..497a83f
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SEAFILE_CLIENT_CERTS_MANAGER_H
+#define SEAFILE_CLIENT_CERTS_MANAGER_H
+
+#include <QHash>
+#include <QSslCertificate>
+
+struct sqlite3;
+struct sqlite3_stmt;
+
+class QUrl;
+
+class CertsManager {
+public:
+    CertsManager();
+    ~CertsManager();
+
+    int start();
+
+    void saveCertificate(const QUrl& url, const QSslCertificate& cert);
+    QSslCertificate getCertificate(const QUrl& url);
+
+private:
+    void loadCertificates();
+    static bool loadCertificatesCB(sqlite3_stmt *stmt, void *data);
+
+    QHash<QString, QSslCertificate> certs_;
+
+    struct sqlite3 *db;
+};
+
+#endif // SEAFILE_CLIENT_CERTS_MANAGER_H
diff --git a/src/configurator.cpp b/src/configurator.cpp
new file mode 100644 (file)
index 0000000..45314d0
--- /dev/null
@@ -0,0 +1,257 @@
+#include <glib.h>
+#include <QCoreApplication>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+#include <QDebug>
+#include <QList>
+#include <QMessageBox>
+#include <QSettings>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "ui/init-seafile-dialog.h"
+
+#if defined(Q_OS_WIN32)
+#include "utils/registry.h"
+#include <shlobj.h>
+#include <shlwapi.h>
+#endif
+
+#include "configurator.h"
+
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+const char *kVirtualDriveGUID = "F817C393-A76E-435E-B6B1-485844BC9C2E";
+const char *kMyComputerNamespacePath =
+    "Software\\Microsoft\\Windows\\CurrentVersion"
+    "\\Explorer\\MyComputer\\Namespace";
+#endif
+
+const char* const kPreconfigureDirectory = "PreconfigureDirectory";
+
+inline QString getPreconfigureDirectory()
+{
+    return expandVars(expandUser(seafApplet->readPreconfigureEntry(kPreconfigureDirectory).toString()));
+}
+
+} // namespace
+
+
+Configurator::Configurator()
+    : ccnet_dir_(defaultCcnetDir()),
+      first_use_(false)
+{
+}
+
+void Configurator::checkInit()
+{
+    if (needInitConfig()) {
+        // first time use
+        initConfig();
+    } else {
+        validateExistingConfig();
+    }
+}
+
+bool Configurator::needInitConfig()
+{
+    if (QDir(ccnet_dir_).exists()) {
+        return false;
+    }
+
+    return true;
+}
+
+void Configurator::initConfig()
+{
+    QString path = QDir::toNativeSeparators(ccnet_dir_);
+    QDir ccnet_dir(ccnet_dir_);
+    if (!ccnet_dir.mkpath(".")) {
+        seafApplet->errorAndExit(tr("Error when creating ccnet configuration"));
+        return;
+    }
+
+    first_use_ = true;
+    initSeafile();
+}
+
+void Configurator::initSeafile()
+{
+    QString preconfigure_dir = getPreconfigureDirectory();
+    if (!preconfigure_dir.isEmpty()) {
+        QDir dir(preconfigure_dir);
+        if (!dir.mkpath(".") ||
+            !dir.mkpath("Seafile/.seafile-data")) {
+            qWarning("[Configurator] unable to create preconfigure directory \"%s\"",
+                     preconfigure_dir.toUtf8().data());
+            qWarning("[Configurator] exiting from an unrecovable error.");
+            seafApplet->warningBox(
+                tr("Unable to create preconfigure directory \"%1\"").arg(
+                    preconfigure_dir.toUtf8().data()));
+            exit(1);
+            return;
+        }
+        first_use_ = true;
+
+        QString seafile_dir = dir.absoluteFilePath("Seafile/.seafile-data");
+        onSeafileDirSet(seafile_dir);
+        return;
+    }
+    InitSeafileDialog dialog;
+    connect(&dialog, SIGNAL(seafileDirSet(const QString&)),
+            this, SLOT(onSeafileDirSet(const QString&)));
+
+    if (dialog.exec() != QDialog::Accepted) {
+        exit(1);
+        return;
+    }
+
+    first_use_ = true;
+}
+
+void Configurator::onSeafileDirSet(const QString& path)
+{
+    // Write seafile dir to <ccnet dir>/seafile.ini
+    QFile seafile_ini(QDir(ccnet_dir_).filePath("seafile.ini"));
+
+    if (!seafile_ini.open(QIODevice::WriteOnly)) {
+        return;
+    }
+
+    seafile_ini.write(path.toUtf8().data());
+
+    seafile_dir_ = path;
+
+    QDir d(path);
+
+    d.cdUp();
+    worktree_ = d.absolutePath();
+
+    setSeafileDirAttributes();
+}
+
+void Configurator::setSeafileDirAttributes()
+{
+#if defined(Q_OS_WIN32)
+    std::wstring seafdir = seafile_dir_.toStdWString();
+
+    // Make seafile-data folder hidden
+    SetFileAttributesW (seafdir.c_str(),
+                        FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+
+    // Set seafdir folder icon.
+    SetFileAttributesW (worktree_.toStdWString().c_str(), FILE_ATTRIBUTE_SYSTEM);
+    QString desktop_ini_path = QDir(worktree_).filePath("Desktop.ini");
+    QFile desktop_ini(desktop_ini_path);
+
+    if (!desktop_ini.open(QIODevice::WriteOnly |  QIODevice::Text)) {
+        return;
+    }
+
+    // QString icon_path = QDir(QCoreApplication::applicationDirPath()).filePath("seafdir.ico");
+
+    // QTextStream out(&desktop_ini);
+    // out << "[.ShellClassInfo]\n";
+    // out << QString("IconFile=%1\n").arg(icon_path);
+    // out << "IconIndex=0\n";
+
+    // // Make the "Desktop.ini" file hidden.
+    // SetFileAttributesW (desktop_ini_path.toStdWString().c_str(),
+    //                     FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+#endif
+}
+
+void Configurator::validateExistingConfig()
+{
+    QFile seafile_ini(QDir(ccnet_dir_).filePath("seafile.ini"));
+    if (!seafile_ini.exists()) {
+        initConfig();
+        return;
+    }
+
+    if (readSeafileIni(&seafile_dir_) < 0 || !QDir(seafile_dir_).exists()) {
+        initSeafile();
+        return;
+    }
+
+    QDir d(seafile_dir_);
+#if !defined(Q_OS_WIN32)
+    QString old_client_wt = d.filePath("../seafile/");
+    if (QFile(old_client_wt).exists()) {
+        // old client
+        worktree_ = QFileInfo(old_client_wt).absoluteFilePath();
+        return;
+    }
+#endif
+
+    d.cdUp();
+    worktree_ = d.absolutePath();
+}
+
+int Configurator::readSeafileIni(QString *content)
+{
+    // First try SEAFILE_DATA_DIR
+    const char *env = g_getenv("SEAFILE_DATA_DIR");
+    if (env) {
+        *content = QString::fromUtf8(env);
+        return 0;
+    }
+
+    QFile seafile_ini(QDir(ccnet_dir_).filePath("seafile.ini"));
+    if (!seafile_ini.exists()) {
+        return -1;
+    }
+
+    if (!seafile_ini.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        seafApplet->errorAndExit(tr("failed to read %1").arg(seafile_ini.fileName()));
+    }
+
+    QTextStream input(&seafile_ini);
+    input.setCodec("UTF-8");
+
+    if (input.atEnd()) {
+        return -1;
+    }
+
+    *content = input.readLine();
+
+    return 0;
+}
+
+void Configurator::installCustomUrlHandler()
+{
+#if defined(Q_OS_WIN32)
+    QList<RegElement> list;
+    HKEY root = HKEY_CURRENT_USER;
+
+    QString exe = QDir::toNativeSeparators(QCoreApplication::applicationFilePath());
+
+    QString cmd = QString("\"%1\" -f ").arg(exe) + " \"%1\"";
+
+    QString classes_seafile = "Software\\Classes\\seafile";
+
+    list.append(RegElement(root, classes_seafile,
+                           "", "URL:seafile Protocol"));
+
+    list.append(RegElement(root, classes_seafile,
+                           "URL Protocol", ""));
+
+    list.append(RegElement(root, classes_seafile + "\\shell",
+                           "", ""));
+
+    list.append(RegElement(root, classes_seafile + "\\shell\\open",
+                           "", ""));
+
+    list.append(RegElement(root, classes_seafile + "\\shell\\open\\command",
+                           "", cmd));
+    for (int i = 0; i < list.size(); i++) {
+        RegElement& reg = list[i];
+        reg.add();
+    }
+#endif
+}
diff --git a/src/configurator.h b/src/configurator.h
new file mode 100644 (file)
index 0000000..7e53dc3
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef SEAFILE_CLIENT_CONFIGURATOR_H
+#define SEAFILE_CLIENT_CONFIGURATOR_H
+
+#include <QObject>
+#include <QString>
+
+/**
+ * Handles seafile configuration initialize
+ */
+class Configurator : public QObject {
+    Q_OBJECT
+
+public:
+    Configurator();
+
+    void checkInit();
+
+    const QString& ccnetDir() const { return ccnet_dir_; }
+    const QString& seafileDir() const { return seafile_dir_; }
+    const QString& worktreeDir() const { return worktree_; }
+    const QString& defaultRepoPath() const { return default_repo_path_; }
+
+    bool firstUse() const { return first_use_; }
+
+public:
+    static void installCustomUrlHandler();
+
+private slots:
+    void onSeafileDirSet(const QString& path);
+
+private:
+    Q_DISABLE_COPY(Configurator)
+
+    void setSeafileDirAttributes();
+
+    bool needInitConfig();
+    void initConfig();
+    void validateExistingConfig();
+    int readSeafileIni(QString *content);
+
+    void initCcnet();
+    void initSeafile();
+
+    QString ccnet_dir_;
+    QString seafile_dir_;
+    QString worktree_;
+
+    QString default_repo_path_;
+
+    bool first_use_;
+};
+
+#endif // SEAFILE_CLIENT_CONFIGURATOR_H
diff --git a/src/crash-handler.cpp b/src/crash-handler.cpp
new file mode 100644 (file)
index 0000000..3c394eb
--- /dev/null
@@ -0,0 +1,138 @@
+#include "crash-handler.h"
+#include <QDir>
+#include <QString>
+#include <cstdio>
+
+#if defined(Q_OS_LINUX)
+#include "client/linux/handler/exception_handler.h"
+#elif defined(Q_OS_WIN32)
+#include "client/windows/handler/exception_handler.h"
+#elif defined(Q_OS_MAC)
+#include "client/mac/handler/exception_handler.h"
+#endif
+
+namespace Breakpad {
+/************************************************************************/
+/* CrashHandlerPrivate                                                  */
+/************************************************************************/
+class CrashHandlerPrivate
+{
+public:
+    CrashHandlerPrivate() {}
+    ~CrashHandlerPrivate() { delete handler; }
+
+    void InitCrashHandler(const QString& dumpPath);
+
+#if defined(Q_OS_WIN32)
+    static bool DumpCallback(const wchar_t* _dump_dir, const wchar_t* _minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool success);
+#elif defined(Q_OS_LINUX)
+    static bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context, bool success);
+#elif defined(Q_OS_MAC)
+    static bool DumpCallback(const char* _dump_dir,const char* _minidump_id,void *context, bool success);
+#endif
+
+    static google_breakpad::ExceptionHandler* handler;
+};
+
+google_breakpad::ExceptionHandler* CrashHandlerPrivate::handler = NULL;
+
+#if defined(Q_OS_WIN32)
+bool CrashHandlerPrivate::DumpCallback(const wchar_t* _dump_dir, const wchar_t* _minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool success);
+#elif defined(Q_OS_LINUX)
+bool CrashHandlerPrivate::DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context, bool success)
+#elif defined(Q_OS_MAC)
+bool CrashHandlerPrivate::DumpCallback(const char* _dump_dir,const char* _minidump_id,void *context, bool success)
+#endif
+{
+    Q_UNUSED(context);
+#if defined(Q_OS_WIN32)
+    Q_UNUSED(_dump_dir);
+    Q_UNUSED(_minidump_id);
+    Q_UNUSED(assertion);
+    Q_UNUSED(exinfo);
+#endif
+    fprintf(stderr, "[breakpad] crash detected\n");
+    /*
+     * unsafe context
+     * don't allocate memory by heap
+     *
+     */
+
+    // CrashHandlerPrivate* self = static_cast<CrashHandlerPrivate*>(context);
+
+    if (!success) {
+      fprintf(stderr, "Failed to generate minidump.\n");
+      return false;
+    }
+
+    fprintf(stderr, "[breakpad] minidump generated\n");
+
+    return success;
+}
+
+    void CrashHandlerPrivate::InitCrashHandler(const QString& dumpPath)
+    {
+        if (handler != NULL)
+            return;
+
+#if defined(Q_OS_WIN32)
+        std::wstring pathAsStr = (const wchar_t*)dumpPath.utf16();
+        handler = new google_breakpad::ExceptionHandler(
+            pathAsStr,
+            /*FilterCallback*/ 0,
+            DumpCallback,
+            /*context*/ this,
+            true
+            );
+#elif defined(Q_OS_LINUX)
+        std::string pathAsStr = dumpPath.toStdString();
+        google_breakpad::MinidumpDescriptor md(pathAsStr);
+        handler = new google_breakpad::ExceptionHandler(
+            md,
+            /*FilterCallback*/ 0,
+            DumpCallback,
+            /*context*/ this,
+            true,
+            -1
+            );
+#elif defined(Q_OS_MAC)
+        std::string pathAsStr = dumpPath.toStdString();
+        handler = new google_breakpad::ExceptionHandler(
+            pathAsStr,
+            /*FilterCallback*/ 0,
+            DumpCallback,
+            /*context*/ this,
+            true,
+            NULL
+            );
+#endif
+        fprintf(stderr, "[breakpad] initialized\n");
+    }
+
+    /************************************************************************/
+    /* CrashHandler                                                         */
+    /************************************************************************/
+    CrashHandler* CrashHandler::instance()
+    {
+        static CrashHandler globalHandler;
+        return &globalHandler;
+    }
+
+    CrashHandler::CrashHandler()
+    {
+        d = new CrashHandlerPrivate();
+    }
+
+    CrashHandler::~CrashHandler()
+    {
+        delete d;
+    }
+
+    void CrashHandler::Init(const QString& reportPath)
+    {
+        if (!QDir(reportPath).mkpath("."))
+            fprintf(stderr, "[breakpad] failed to create crash directory\n");
+        d->InitCrashHandler(reportPath);
+    }
+}
+
diff --git a/src/crash-handler.h b/src/crash-handler.h
new file mode 100644 (file)
index 0000000..a0cbff4
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef SEAFILE_CLIENT_CRASH_HANDLER
+#define SEAFILE_CLIENT_CRASH_HANDLER
+#ifdef SEAFILE_CLIENT_HAS_CRASH_REPORTER
+#include <QString>
+
+namespace Breakpad {
+
+class CrashHandlerPrivate;
+class CrashHandler
+{
+public:
+    static CrashHandler* instance();
+    void Init(const QString& reportPath);
+private:
+    Q_DISABLE_COPY(CrashHandler)
+
+    CrashHandler();
+    ~CrashHandler();
+    CrashHandlerPrivate* d;
+};
+}
+#endif // SEAFILE_CLIENT_HAS_CRASH_REPORTER
+#endif // SEAFILE_CLIENT_CRASH_HANDLER
+
diff --git a/src/customization-service.cpp b/src/customization-service.cpp
new file mode 100644 (file)
index 0000000..64e33db
--- /dev/null
@@ -0,0 +1,79 @@
+#include <QTimer>
+#include <QDir>
+#include <QNetworkDiskCache>
+
+#include "customization-service.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "configurator.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+
+
+SINGLETON_IMPL(CustomizationService)
+
+CustomizationService::CustomizationService(QObject* parent) : QObject(parent)
+{
+    disk_cache_ = new QNetworkDiskCache();
+}
+
+void CustomizationService::start()
+{
+    disk_cache_->setCacheDirectory(
+        QDir(seafApplet->configurator()->seafileDir())
+            .filePath("customization"));
+}
+
+QPixmap CustomizationService::getServerLogo(const Account& account)
+{
+    QPixmap logo = QPixmap(":/images/seafile-24.png");
+    if (account.serverInfo.customLogo.isEmpty()) {
+        return logo;
+    }
+
+    QUrl url = account.getAbsoluteUrl(account.serverInfo.customLogo);
+    QIODevice* buf = disk_cache_->data(url);
+    if (buf) {
+        logo.loadFromData(buf->readAll());
+        buf->close();
+        delete buf;
+    }
+
+    if (!reqs_.contains(url.toString())) {
+        FetchCustomLogoRequest* req = new FetchCustomLogoRequest(url);
+        connect(req,
+                SIGNAL(success(const QUrl&)),
+                this,
+                SLOT(onServerLogoFetched(const QUrl&)));
+        connect(req,
+                SIGNAL(failed(const ApiError&)),
+                this,
+                SLOT(onServerLogoFetchFailed(const ApiError&)));
+
+        req->send();
+        reqs_[url.toString()] = req;
+    }
+
+    return logo;
+}
+
+void CustomizationService::onServerLogoFetched(const QUrl& url)
+{
+    emit(serverLogoFetched(url));
+    FetchCustomLogoRequest* req =
+        qobject_cast<FetchCustomLogoRequest*>(sender());
+    cleanUpRequest(req);
+}
+
+void CustomizationService::onServerLogoFetchFailed(const ApiError& error)
+{
+    FetchCustomLogoRequest* req =
+        qobject_cast<FetchCustomLogoRequest*>(sender());
+    cleanUpRequest(req);
+}
+
+void CustomizationService::cleanUpRequest(FetchCustomLogoRequest* req)
+{
+    reqs_.remove(req->url().toString());
+    req->deleteLater();
+}
diff --git a/src/customization-service.h b/src/customization-service.h
new file mode 100644 (file)
index 0000000..8d27cd4
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef SEAFILE_CLIENT_CUSTOMIAZATION_SERVICE_H
+#define SEAFILE_CLIENT_CUSTOMIAZATION_SERVICE_H
+
+#include <QObject>
+#include <QUrl>
+#include <QPixmap>
+#include <QHash>
+
+#include "utils/singleton.h"
+#include "account.h"
+
+class QNetworkDiskCache;
+
+class FetchCustomLogoRequest;
+class ApiError;
+
+class CustomizationService : public QObject
+{
+    Q_OBJECT
+    SINGLETON_DEFINE(CustomizationService)
+public:
+    void start();
+
+    // Read the logo from the disk cache if exists, otherwise return a default
+    // logo and send a request to fetch the logo.
+    QPixmap getServerLogo(const Account& account);
+
+    QNetworkDiskCache *diskCache() const { return disk_cache_; }
+
+signals:
+    void serverLogoFetched(const QUrl& url);
+
+private slots:
+    void onServerLogoFetched(const QUrl& url);
+    void onServerLogoFetchFailed(const ApiError& error);
+
+private:
+    Q_DISABLE_COPY(CustomizationService)
+    CustomizationService(QObject* parent = 0);
+
+    void cleanUpRequest(FetchCustomLogoRequest *req);
+
+    QHash<QString, FetchCustomLogoRequest*> reqs_;
+
+    QNetworkDiskCache* disk_cache_;
+};
+
+
+#endif // SEAFILE_CLIENT_CUSTOMIAZATION_SERVICE_H
diff --git a/src/daemon-mgr.cpp b/src/daemon-mgr.cpp
new file mode 100644 (file)
index 0000000..12ba296
--- /dev/null
@@ -0,0 +1,215 @@
+#include <glib-object.h>
+#include <cstdio>
+#include <cstdlib>
+#include <QTimer>
+#include <QStringList>
+#include <QString>
+#include <QDebug>
+#include <QDir>
+#include <QCoreApplication>
+
+#include "utils/utils.h"
+#include "utils/process.h"
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "daemon-mgr.h"
+
+namespace {
+
+const int kConnDaemonIntervalMilli = 1000;
+const int kMaxDaemonReadyCheck = 15;
+
+const int kDaemonRestartInternvalMSecs = 2000;
+const int kDaemonRestartMaxRetries = 10;
+
+#if defined(Q_OS_WIN32)
+const char *kSeafileDaemonExecutable = "seaf-daemon.exe";
+#else
+const char *kSeafileDaemonExecutable = "seaf-daemon";
+#endif
+
+typedef enum {
+    DAEMON_INIT = 0,
+    DAEMON_STARTING,
+    DAEMON_CONNECTING,
+    DAEMON_CONNECTED,
+    DAEMON_DEAD,
+    SEAFILE_EXITING,
+    MAX_STATE,
+} DaemonState;
+
+const char *DaemonStateStrs[] = {
+    "init",
+    "starting",
+    "connecting",
+    "connected",
+    "dead",
+    "seafile_exiting"
+};
+
+const char *stateToStr(int state)
+{
+    if (state < 0 || state >= MAX_STATE) {
+        return "";
+    }
+    return DaemonStateStrs[state];
+}
+
+bool seafileRpcReady() {
+    SeafileRpcClient rpc;
+    if (!rpc.tryConnectDaemon()) {
+        return false;
+    }
+
+    QString str;
+    return rpc.seafileGetConfig("use_proxy", &str) == 0;
+}
+
+
+} // namespace
+
+
+
+DaemonManager::DaemonManager()
+    : seaf_daemon_(nullptr)
+{
+    current_state_ = DAEMON_INIT;
+    first_start_ = true;
+    restart_retried_ = 0;
+
+    conn_daemon_timer_ = new QTimer(this);
+    connect(conn_daemon_timer_, SIGNAL(timeout()), this, SLOT(checkDaemonReady()));
+
+    connect(qApp, SIGNAL(aboutToQuit()),
+            this, SLOT(systemShutDown()));
+}
+
+DaemonManager::~DaemonManager() {
+    stopDaemon();
+}
+
+void DaemonManager::restartSeafileDaemon()
+{
+    if (current_state_ == SEAFILE_EXITING) {
+        return;
+    }
+
+    qWarning("Trying to restart seafile daemon");
+    startSeafileDaemon();
+}
+
+void DaemonManager::startSeafileDaemon()
+{
+    if (first_start_) {
+        shutdown_process (kSeafileDaemonExecutable);
+    }
+
+    seaf_daemon_ = new QProcess(this);
+    connect(seaf_daemon_, SIGNAL(started()), this, SLOT(onDaemonStarted()));
+    connect(seaf_daemon_, SIGNAL(finished(int, QProcess::ExitStatus)),
+            SLOT(onDaemonFinished(int, QProcess::ExitStatus)));
+
+    const QString config_dir = seafApplet->configurator()->ccnetDir();
+    const QString seafile_dir = seafApplet->configurator()->seafileDir();
+    const QString worktree_dir = seafApplet->configurator()->worktreeDir();
+
+    QStringList args;
+    args << "-c" << config_dir << "-d" << seafile_dir << "-w" << worktree_dir;
+    seaf_daemon_->start(RESOURCE_PATH(kSeafileDaemonExecutable), args);
+    qWarning() << "starting seaf-daemon: " << args;
+    transitionState(DAEMON_STARTING);
+}
+
+void DaemonManager::systemShutDown()
+{
+    transitionState(SEAFILE_EXITING);
+}
+
+void DaemonManager::onDaemonStarted()
+{
+    qDebug("seafile daemon is now running, checking if the service is ready");
+    conn_daemon_timer_->start(kConnDaemonIntervalMilli);
+    transitionState(DAEMON_CONNECTING);
+}
+
+void DaemonManager::checkDaemonReady()
+{
+    QString str;
+    // Because some settings need to be loaded from seaf daemon, we only emit
+    // the "daemonStarted" signal after we're sure the daemon rpc is ready.
+    if (seafileRpcReady()) {
+        qDebug("seaf daemon is ready");
+        conn_daemon_timer_->stop();
+        transitionState(DAEMON_CONNECTED);
+        restart_retried_ = 0;
+        if (first_start_) {
+            first_start_ = false;
+            emit daemonStarted();
+        } else {
+            emit daemonRestarted();
+        }
+        return;
+    }
+    qDebug("seaf daemon is not ready");
+    static int maxcheck = 0;
+    if (++maxcheck > kMaxDaemonReadyCheck) {
+        qWarning("seafile rpc is not ready after %d retry, abort", maxcheck);
+        seafApplet->errorAndExit(tr("%1 client failed to initialize").arg(getBrand()));
+    }
+}
+
+void DaemonManager::onDaemonFinished(int exit_code, QProcess::ExitStatus exit_status)
+{
+    qWarning("Seafile daemon process %s with code %d ",
+             (current_state_ != SEAFILE_EXITING &&
+              exit_status == QProcess::CrashExit)
+                 ? "crashed"
+                 : "exited normally",
+             exit_code);
+
+
+    if (current_state_ == DAEMON_CONNECTING) {
+        conn_daemon_timer_->stop();
+        scheduleRestartDaemon();
+    } else if (current_state_ != SEAFILE_EXITING) {
+        transitionState(DAEMON_DEAD);
+        emit daemonDead();
+        scheduleRestartDaemon();
+    }
+}
+
+void DaemonManager::stopDaemon()
+{
+    conn_daemon_timer_->stop();
+    if (seaf_daemon_) {
+        qWarning("[Daemon Mgr] stopping seafile daemon");
+        // TODO: add an "exit" rpc in seaf-daemon to exit gracefully?
+        seaf_daemon_->kill();
+        seaf_daemon_->waitForFinished(50);
+        seaf_daemon_ = nullptr;
+    }
+}
+
+void DaemonManager::scheduleRestartDaemon()
+{
+    // When the daemon crashes when we first start seafile, we should
+    // not retry too many times, because during the retry nothing
+    // would be shown to the user and would confuse him.
+    int max_retry = 2;
+    if (seafApplet->rpcClient() && seafApplet->rpcClient()->isConnected()) {
+        max_retry = kDaemonRestartMaxRetries;
+    }
+    if (++restart_retried_ >= max_retry) {
+        qWarning("reaching max tries of restarting seafile daemon, aborting");
+        seafApplet->errorAndExit(tr("%1 exited unexpectedly").arg(getBrand()));
+        return;
+    }
+    QTimer::singleShot(kDaemonRestartInternvalMSecs, this, SLOT(restartSeafileDaemon()));
+}
+
+void DaemonManager::transitionState(int new_state)
+{
+    qDebug("daemon mgr: %s => %s", stateToStr(current_state_), stateToStr(new_state));
+    current_state_ = new_state;
+}
diff --git a/src/daemon-mgr.h b/src/daemon-mgr.h
new file mode 100644 (file)
index 0000000..310987e
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef SEAFILE_CLIENT_DAEMON_MANAGER_H
+#define SEAFILE_CLIENT_DAEMON_MANAGER_H
+
+#include <QObject>
+#include <QProcess>
+
+class QTimer;
+
+/**
+ * Start/Monitor seafile daemon
+ */
+class DaemonManager : public QObject {
+    Q_OBJECT
+
+public:
+    DaemonManager();
+    ~DaemonManager();
+    void startSeafileDaemon();
+
+signals:
+    void daemonStarted();
+
+    void daemonDead();
+    void daemonRestarted();
+
+private slots:
+    void onDaemonStarted();
+    void onDaemonFinished(int exit_code, QProcess::ExitStatus exit_status);
+    void systemShutDown();
+    void checkDaemonReady();
+    void restartSeafileDaemon();
+
+private:
+    Q_DISABLE_COPY(DaemonManager)
+
+    void stopDaemon();
+    void scheduleRestartDaemon();
+    void transitionState(int new_state);
+
+    QProcess *seaf_daemon_;
+    QTimer *conn_daemon_timer_;
+
+    int current_state_;
+    // Used to decide whether to emit daemonStarted or daemonRestarted
+    bool first_start_;
+    int restart_retried_;
+};
+
+#endif // SEAFILE_CLIENT_DAEMON_MANAGER_H
diff --git a/src/events-service.cpp b/src/events-service.cpp
new file mode 100644 (file)
index 0000000..3be66db
--- /dev/null
@@ -0,0 +1,189 @@
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "api/requests.h"
+#include "events-service.h"
+
+namespace {
+
+const int kEventsPerPageForNewApi = 25;
+} // namespace
+
+EventsService* EventsService::singleton_;
+
+EventsService* EventsService::instance()
+{
+    if (singleton_ == NULL) {
+        static EventsService instance;
+        singleton_ = &instance;
+    }
+
+    return singleton_;
+}
+
+EventsService::EventsService(QObject *parent)
+    : QObject(parent)
+{
+    get_events_req_ = NULL;
+    get_file_activities_req_ = NULL;
+    next_ = -1;
+    in_refresh_ = false;
+}
+
+void EventsService::start()
+{
+}
+
+void EventsService::stop()
+{
+}
+
+void EventsService::refresh()
+{
+    if (seafApplet->accountManager()->currentAccount().isPro()) {
+        sendRequest(false);
+    }
+}
+
+void EventsService::sendRequest(bool is_load_more)
+{
+    if (in_refresh_) {
+        return;
+    }
+
+    const Account& account = seafApplet->accountManager()->currentAccount();
+    if (!account.isValid()) {
+        in_refresh_ = false;
+        return;
+    }
+
+    // server version begin 7.0.0 support new api
+    bool is_support_new_file_activities_api = account.isAtLeastVersion(7, 0, 0);
+    in_refresh_ = true;
+
+    if (!is_support_new_file_activities_api) {
+        if (get_events_req_) {
+            get_events_req_->deleteLater();
+        }
+
+        if (!is_load_more) {
+            events_.clear();
+            next_ = -1;
+        }
+
+        get_events_req_ = new GetEventsRequest(account, next_);
+
+        connect(get_events_req_, SIGNAL(success(const std::vector<SeafEvent>&, int)),
+                this, SLOT(onRefreshSuccess(const std::vector<SeafEvent>&, int)));
+
+        connect(get_events_req_, SIGNAL(failed(const ApiError&)),
+                this, SLOT(onRefreshFailed(const ApiError&)));
+
+        get_events_req_->send();
+    } else {
+        if (get_file_activities_req_) {
+            get_file_activities_req_->deleteLater();
+        }
+
+        if (!is_load_more) {
+            events_.clear();
+            next_ = 1;
+        } else {
+            ++next_;
+        }
+
+        get_file_activities_req_ = new GetEventsRequestV2(account, next_);
+
+        connect(get_file_activities_req_, SIGNAL(success(const std::vector<SeafEvent>&)),
+                this, SLOT(onRefreshSuccessV2(const std::vector<SeafEvent>&)));
+
+        connect(get_file_activities_req_, SIGNAL(failed(const ApiError&)),
+                this, SLOT(onRefreshFailed(const ApiError&)));
+
+        get_file_activities_req_->send();
+    }
+
+}
+
+void EventsService::loadMore()
+{
+    sendRequest(true);
+}
+
+void EventsService::onRefreshSuccess(const std::vector<SeafEvent>& events, int new_offset)
+{
+    in_refresh_ = false;
+
+    const std::vector<SeafEvent> new_events = handleEventsOffset(events);
+
+    bool is_loading_more = next_ > 0;
+    bool has_more = new_offset > 0;
+    next_ = new_offset;
+    emit refreshSuccess(new_events, is_loading_more, has_more);
+}
+
+void EventsService::onRefreshSuccessV2(const std::vector<SeafEvent>& events)
+{
+    in_refresh_ = false;
+
+    const std::vector<SeafEvent> new_events = handleEventsOffset(events);
+
+    bool has_more = events.size() == kEventsPerPageForNewApi;
+    bool is_loading_more = next_ > 1;
+    if (!has_more) {
+        next_ = -1;
+    }
+
+    emit refreshSuccess(new_events, is_loading_more, has_more);
+}
+
+// We use the "offset" param as the starting point of loading more events, but
+// if there are new events on the server, the offset would be inaccurate.
+const std::vector<SeafEvent>
+EventsService::handleEventsOffset(const std::vector<SeafEvent>& new_events)
+{
+    if (events_.empty()) {
+        events_ = new_events;
+        return events_;
+    }
+
+    const SeafEvent& last = events_[events_.size() - 1];
+
+    int i = 0, n = new_events.size();
+
+    for (i = 0; i < n; i++) {
+        const SeafEvent& event = new_events[i];
+        if (event.timestamp < last.timestamp) {
+            break;
+        } else if (event.commit_id == last.commit_id) {
+            continue;
+        } else {
+            continue;
+        }
+    }
+
+    std::vector<SeafEvent> ret;
+
+    while (i < n) {
+        SeafEvent event = new_events[i++];
+        events_.push_back(event);
+        ret.push_back(event);
+    }
+
+    return ret;
+}
+
+void EventsService::onRefreshFailed(const ApiError& error)
+{
+    in_refresh_ = false;
+
+    emit refreshFailed(error);
+}
+
+void EventsService::refresh(bool force)
+{
+    if (force) {
+        in_refresh_ = false;
+    }
+
+    refresh();
+}
diff --git a/src/events-service.h b/src/events-service.h
new file mode 100644 (file)
index 0000000..cd5c61c
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef SEAFILE_CLIENT_EVENTS_SERVICE_H
+#define SEAFILE_CLIENT_EVENTS_SERVICE_H
+
+#include <vector>
+#include <QObject>
+
+#include "api/event.h"
+
+class ApiError;
+class GetEventsRequest;
+class GetEventsRequestV2;
+
+class EventsService : public QObject
+{
+    Q_OBJECT
+public:
+    static EventsService* instance();
+
+    void start();
+    void stop();
+
+    void refresh(bool force);
+
+    void loadMore();
+
+    // accessors
+    const std::vector<SeafEvent>& events() const { return events_; }
+
+    bool hasMore() const { return next_ > 0; }
+
+public slots:
+    void refresh();
+
+private slots:
+    void onRefreshSuccess(const std::vector<SeafEvent>& events, int more_offset);
+    void onRefreshSuccessV2(const std::vector<SeafEvent>& events);
+    void onRefreshFailed(const ApiError& error);
+
+signals:
+    void refreshSuccess(const std::vector<SeafEvent>& events, bool is_loading_more, bool has_more);
+    void refreshFailed(const ApiError& error);
+
+private:
+    Q_DISABLE_COPY(EventsService)
+
+    EventsService(QObject *parent=0);
+    void sendRequest(bool is_loading_more);
+
+    static EventsService *singleton_;
+
+    const std::vector<SeafEvent> handleEventsOffset(const std::vector<SeafEvent>& new_events);
+
+    GetEventsRequest *get_events_req_;
+
+    GetEventsRequestV2 *get_file_activities_req_;
+
+    std::vector<SeafEvent> events_;
+
+    bool in_refresh_;
+
+    // for old api, it's an offset
+    // for new api, it's the next page number
+    int next_;
+};
+
+
+#endif // SEAFILE_CLIENT_EVENTS_SERVICE_H
diff --git a/src/ext-handler.cpp b/src/ext-handler.cpp
new file mode 100644 (file)
index 0000000..55da264
--- /dev/null
@@ -0,0 +1,686 @@
+#include <winsock2.h>
+#include <windows.h>
+#include <io.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <userenv.h>
+
+#include <string>
+#include <QMutexLocker>
+#include <QScopedPointer>
+#include <QList>
+#include <QVector>
+#include <QDir>
+#include <QTimer>
+#include <QDateTime>
+#include <QDebug>
+
+#include "filebrowser/file-browser-requests.h"
+#include "filebrowser/sharedlink-dialog.h"
+#include "filebrowser/seafilelink-dialog.h"
+#include "ui/private-share-dialog.h"
+#include "rpc/rpc-client.h"
+#include "repo-service.h"
+#include "api/api-error.h"
+#include "seafile-applet.h"
+#include "daemon-mgr.h"
+#include "account-mgr.h"
+#include "settings-mgr.h"
+#include "utils/utils.h"
+#include "utils/utils-win.h"
+#include "auto-login-service.h"
+#include "ext-handler.h"
+
+namespace {
+
+const char *kSeafExtPipeName = "\\\\.\\pipe\\seafile_ext_pipe_";
+const int kPipeBufSize = 1024;
+
+const quint64 kReposInfoCacheMSecs = 2000;
+
+bool
+extPipeReadN (HANDLE pipe, void *buf, size_t len)
+{
+    DWORD bytes_read;
+    bool success = ReadFile(
+        pipe,                  // handle to pipe
+        buf,                   // buffer to receive data
+        (DWORD)len,            // size of buffer
+        &bytes_read,           // number of bytes read
+        NULL);                 // not overlapped I/O
+
+    if (!success || bytes_read != (DWORD)len) {
+        DWORD error = GetLastError();
+        if (error == ERROR_BROKEN_PIPE) {
+            qDebug("[ext] connection closed by extension\n");
+        } else {
+            qWarning("[ext] Failed to read command from extension(), "
+                     "error code %lu\n", error);
+        }
+        return false;
+    }
+
+    return true;
+}
+
+bool
+extPipeWriteN(HANDLE pipe, void *buf, size_t len)
+{
+    DWORD bytes_written;
+    bool success = WriteFile(
+        pipe,                  // handle to pipe
+        buf,                   // buffer to receive data
+        (DWORD)len,            // size of buffer
+        &bytes_written,        // number of bytes written
+        NULL);                 // not overlapped I/O
+
+    if (!success || bytes_written != (DWORD)len) {
+        DWORD error = GetLastError();
+        if (error == ERROR_BROKEN_PIPE) {
+            qDebug("[ext] connection closed by extension\n");
+        } else {
+            qWarning("[ext] Failed to read command from extension(), "
+                     "error code %lu\n", error);
+        }
+        return false;
+    }
+
+    FlushFileBuffers(pipe);
+    return true;
+}
+
+/**
+ * Replace "\" with "/", and remove the trailing slash
+ */
+QString normalizedPath(const QString& path)
+{
+    QString p = QDir::fromNativeSeparators(path);
+    if (p.endsWith("/")) {
+        p = p.left(p.size() - 1);
+    }
+    return p;
+}
+
+std::string formatErrorMessage()
+{
+    DWORD error_code = ::GetLastError();
+    if (error_code == 0) {
+        return "no error";
+    }
+    char buf[256] = {0};
+    ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+                    NULL,
+                    error_code,
+                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                    buf,
+                    sizeof(buf) - 1,
+                    NULL);
+    return buf;
+}
+
+QString repoStatus(const LocalRepo& repo)
+{
+    QString status = "normal";
+    if (!repo.auto_sync) {
+        status = "paused";
+    } else if (repo.sync_state == LocalRepo::SYNC_STATE_ING) {
+        status = "syncing";
+    } else if (repo.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+        status = "error";
+    }
+
+    // qDebug("repo %s (%s, %s): %s", repo.name.toUtf8().data(),
+    //        repo.sync_state_str.toUtf8().data(),
+    //        repo.sync_error_str.toUtf8().data(),
+    //        status.toUtf8().data());
+
+    return status;
+}
+
+} // namespace
+
+
+SINGLETON_IMPL(SeafileExtensionHandler)
+
+SeafileExtensionHandler::SeafileExtensionHandler()
+: started_(false)
+{
+    listener_thread_ = new ExtConnectionListenerThread;
+
+    connect(listener_thread_, SIGNAL(generateShareLink(const QString&, const QString&, bool, bool)),
+            this, SLOT(generateShareLink(const QString&, const QString&, bool, bool)));
+
+    connect(listener_thread_, SIGNAL(lockFile(const QString&, const QString&, bool)),
+            this, SLOT(lockFile(const QString&, const QString&, bool)));
+
+    connect(listener_thread_, SIGNAL(privateShare(const QString&, const QString&, bool)),
+            this, SLOT(privateShare(const QString&, const QString&, bool)));
+
+    connect(listener_thread_, SIGNAL(openUrlWithAutoLogin(const QUrl&)),
+            this, SLOT(openUrlWithAutoLogin(const QUrl&)));
+}
+
+void SeafileExtensionHandler::start()
+{
+    listener_thread_->start();
+    ReposInfoCache::instance()->start();
+    started_ = true;
+}
+
+void SeafileExtensionHandler::stop()
+{
+    if (started_) {
+        // Before seafile client exits, tell the shell to clean all the file
+        // status icons
+        SHChangeNotify (SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+    }
+}
+
+void SeafileExtensionHandler::generateShareLink(const QString& repo_id,
+                                                const QString& path_in_repo,
+                                                bool is_file,
+                                                bool internal)
+{
+    // qDebug("path_in_repo: %s", path_in_repo.toUtf8().data());
+    const Account account = seafApplet->accountManager()->getAccountByRepo(repo_id);
+    if (!account.isValid()) {
+        return;
+    }
+
+    if (internal) {
+        QString path = path_in_repo;
+        if (!is_file && !path.endsWith("/")) {
+            path += "/";
+        }
+        GetSmartLinkRequest *req = new GetSmartLinkRequest(account, repo_id, path, !is_file);
+        connect(req, SIGNAL(success(const QString&)),
+                this, SLOT(onGetSmartLinkSuccess(const QString&)));
+        connect(req, SIGNAL(failed(const ApiError&)),
+                this, SLOT(onGetSmartLinkFailed(const ApiError&)));
+
+        req->send();
+    } else {
+        GetSharedLinkRequest *req = new GetSharedLinkRequest(
+            account, repo_id, path_in_repo, is_file);
+
+        connect(req, SIGNAL(success(const QString&, const QString&)),
+                this, SLOT(onShareLinkGenerated(const QString&)));
+
+        req->send();
+    }
+}
+
+void SeafileExtensionHandler::onGetSmartLinkSuccess(const QString& smart_link)
+{
+    GetSmartLinkRequest *req = (GetSmartLinkRequest *)(sender());
+    SeafileLinkDialog *dialog = new SeafileLinkDialog(smart_link, NULL);
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->show();
+    dialog->raise();
+    dialog->activateWindow();
+    req->deleteLater();
+}
+
+void SeafileExtensionHandler::onGetSmartLinkFailed(const ApiError& error)
+{
+    seafApplet->warningBox(tr("Failed to get link"));
+}
+
+void SeafileExtensionHandler::lockFile(const QString& repo_id,
+                                       const QString& path_in_repo,
+                                       bool lock)
+{
+    // qDebug("path_in_repo: %s", path_in_repo.toUtf8().data());
+    const Account account = seafApplet->accountManager()->getAccountByRepo(repo_id);
+    if (!account.isValid()) {
+        return;
+    }
+
+    LockFileRequest *req = new LockFileRequest(
+        account, repo_id, path_in_repo, lock);
+
+    connect(req, SIGNAL(success(const QString&)),
+            this, SLOT(onLockFileSuccess()));
+    connect(req, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onLockFileFailed(const ApiError&)));
+
+    req->send();
+}
+
+void SeafileExtensionHandler::privateShare(const QString& repo_id,
+                                           const QString& path_in_repo,
+                                           bool to_group)
+{
+    const Account account = seafApplet->accountManager()->getAccountByRepo(repo_id);
+    if (!account.isValid()) {
+        qWarning("no account found for repo %12s", repo_id.toUtf8().data());
+        return;
+    }
+
+    LocalRepo repo;
+    seafApplet->rpcClient()->getLocalRepo(repo_id, &repo);
+    PrivateShareDialog *dialog = new PrivateShareDialog(account, repo_id, repo.name,
+                                                        path_in_repo, to_group,
+                                                        NULL);
+
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->show();
+    dialog->raise();
+    dialog->activateWindow();
+}
+
+void SeafileExtensionHandler::openUrlWithAutoLogin(const QUrl& url)
+{
+    AutoLoginService::instance()->startAutoLogin(url.toString());
+}
+
+void SeafileExtensionHandler::onShareLinkGenerated(const QString& link)
+{
+    SharedLinkDialog *dialog = new SharedLinkDialog(link, NULL);
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->show();
+    dialog->raise();
+    dialog->activateWindow();
+}
+
+void SeafileExtensionHandler::onLockFileSuccess()
+{
+    LockFileRequest *req = qobject_cast<LockFileRequest *>(sender());
+    LocalRepo repo;
+    seafApplet->rpcClient()->getLocalRepo(req->repoId(), &repo);
+    if (repo.isValid()) {
+        seafApplet->rpcClient()->markFileLockState(req->repoId(), req->path(), req->lock());
+        QString path = QDir::toNativeSeparators(QDir(repo.worktree).absoluteFilePath(req->path().mid(1)));
+        SHChangeNotify(SHCNE_ATTRIBUTES, SHCNF_PATH, path.toUtf8().data(), NULL);
+    }
+}
+
+void SeafileExtensionHandler::onLockFileFailed(const ApiError& error)
+{
+    LockFileRequest *req = qobject_cast<LockFileRequest *>(sender());
+    QString str = req->lock() ? tr("Failed to lock file") : tr("Failed to unlock file");
+    seafApplet->warningBox(QString("%1: %2").arg(str, error.toString()));
+}
+
+
+void ExtConnectionListenerThread::run()
+{
+    std::string local_pipe_name = utils::win::getLocalPipeName(kSeafExtPipeName);
+    qWarning("[ext listener] listening on %s", local_pipe_name.c_str());
+    while (1) {
+        HANDLE pipe = INVALID_HANDLE_VALUE;
+        bool connected = false;
+
+        pipe = CreateNamedPipe(
+            local_pipe_name.c_str(),  // pipe name
+            PIPE_ACCESS_DUPLEX,       // read/write access
+            PIPE_TYPE_MESSAGE |       // message type pipe
+            PIPE_READMODE_MESSAGE |   // message-read mode
+            PIPE_WAIT,                // blocking mode
+            PIPE_UNLIMITED_INSTANCES, // max. instances
+            kPipeBufSize,             // output buffer size
+            kPipeBufSize,             // input buffer size
+            0,                        // client time-out
+            NULL);                    // default security attribute
+
+        if (pipe == INVALID_HANDLE_VALUE) {
+            qWarning ("Failed to create named pipe, GLE=%lu\n",
+                      GetLastError());
+            return;
+        }
+
+        /* listening on this pipe */
+        connected = ConnectNamedPipe(pipe, NULL) ?
+            true : (GetLastError() == ERROR_PIPE_CONNECTED);
+
+        if (!connected) {
+            qWarning ("Failed on ConnectNamedPipe(), GLE=%lu\n",
+                      GetLastError());
+            CloseHandle(pipe);
+            return;
+        }
+
+        qDebug ("[ext pipe] Accepted an extension pipe client\n");
+        servePipeInNewThread(pipe);
+    }
+}
+
+void ExtConnectionListenerThread::servePipeInNewThread(HANDLE pipe)
+{
+    ExtCommandsHandler *t = new ExtCommandsHandler(pipe);
+
+    connect(t, SIGNAL(generateShareLink(const QString&, const QString&, bool, bool)),
+            this, SIGNAL(generateShareLink(const QString&, const QString&, bool, bool)));
+    connect(t, SIGNAL(lockFile(const QString&, const QString&, bool)),
+            this, SIGNAL(lockFile(const QString&, const QString&, bool)));
+    connect(t, SIGNAL(privateShare(const QString&, const QString&, bool)),
+            this, SIGNAL(privateShare(const QString&, const QString&, bool)));
+    connect(t, SIGNAL(openUrlWithAutoLogin(const QUrl&)),
+            this, SIGNAL(openUrlWithAutoLogin(const QUrl&)));
+    t->start();
+}
+
+ExtCommandsHandler::ExtCommandsHandler(HANDLE pipe)
+{
+    pipe_ = pipe;
+}
+
+void ExtCommandsHandler::run()
+{
+    while (1) {
+        QStringList args;
+        if (!readRequest(&args)) {
+            qWarning ("failed to read request from shell extension: %s",
+                      formatErrorMessage().c_str());
+            break;
+        }
+
+        QString cmd = args.takeAt(0);
+        QString resp;
+        if (cmd == "list-repos") {
+            resp = handleListRepos(args);
+        } else if (cmd == "get-share-link") {
+            handleGenShareLink(args, false);
+        } else if (cmd == "get-internal-link") {
+            handleGenShareLink(args, true);
+        } else if (cmd == "get-file-status") {
+            resp = handleGetFileStatus(args);
+        } else if (cmd == "lock-file") {
+            handleLockFile(args, true);
+        } else if (cmd == "unlock-file") {
+            handleLockFile(args, false);
+        } else if (cmd == "private-share-to-group") {
+            handlePrivateShare(args, true);
+        } else if (cmd == "private-share-to-user") {
+            handlePrivateShare(args, false);
+        } else if (cmd == "show-history") {
+            handleShowHistory(args);
+        } else {
+            qWarning ("[ext] unknown request command: %s", cmd.toUtf8().data());
+        }
+
+        if (!sendResponse(resp)) {
+            qWarning ("failed to write response to shell extension: %s",
+                      formatErrorMessage().c_str());
+            break;
+        }
+    }
+
+    qDebug ("An extension client is disconnected: GLE=%lu\n",
+            GetLastError());
+    DisconnectNamedPipe(pipe_);
+    CloseHandle(pipe_);
+}
+
+bool ExtCommandsHandler::readRequest(QStringList *args)
+{
+    uint32_t len = 0;
+    if (!extPipeReadN(pipe_, &len, sizeof(len)) || len == 0)
+        return false;
+
+    QScopedArrayPointer<char> buf(new char[len + 1]);
+    buf.data()[len] = 0;
+    if (!extPipeReadN(pipe_, buf.data(), len))
+        return false;
+
+    QStringList list = QString::fromUtf8(buf.data()).split('\t');
+    if (list.empty()) {
+        qWarning("[ext] got an empty request");
+        return false;
+    }
+    *args = list;
+    return true;
+}
+
+bool ExtCommandsHandler::sendResponse(const QString& resp)
+{
+    QByteArray raw_resp = resp.toUtf8();
+    uint32_t len = raw_resp.length();
+
+    if (!extPipeWriteN(pipe_, &len, sizeof(len))) {
+        return false;
+    }
+    if (len > 0) {
+        if (!extPipeWriteN(pipe_, raw_resp.data(), len)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+QList<LocalRepo> ExtCommandsHandler::listLocalRepos(quint64 ts)
+{
+    return ReposInfoCache::instance()->getReposInfo(ts);
+}
+
+void ExtCommandsHandler::handleGenShareLink(const QStringList& args, bool internal)
+{
+    if (args.size() != 1) {
+        return;
+    }
+    QString path = normalizedPath(args[0]);
+    foreach (const LocalRepo& repo, listLocalRepos()) {
+        QString wt = normalizedPath(repo.worktree);
+        // qDebug("path: %s, repo: %s", path.toUtf8().data(), wt.toUtf8().data());
+        if (path.length() > wt.length() && path.startsWith(wt) && path.at(wt.length()) == '/') {
+            QString path_in_repo = path.mid(wt.size());
+            bool is_file = QFileInfo(path).isFile();
+            emit generateShareLink(repo.id, path_in_repo, is_file, internal);
+            break;
+        }
+    }
+}
+
+QString ExtCommandsHandler::handleListRepos(const QStringList& args)
+{
+    if (args.size() < 1) {
+        return "";
+    }
+    bool ok;
+    quint64 ts = args[0].toULongLong(&ok);
+    if (!ok) {
+        return "";
+    }
+
+    // In older versions of the shell ext it sends one argument (the
+    // cache timestamp) and expects to see exactly six fields.
+    bool new_version = args.size() > 1;
+    QStringList infos;
+    // TODO: We should use json for the requests/responses between
+    // shell-ext <=> seafile client
+    foreach (const LocalRepo& repo, listLocalRepos(ts)) {
+        QStringList fields;
+        QString file_lock = repo.account.isAtLeastProVersion(4, 3, 0)
+                                ? "file-lock-supported"
+                                : "file-lock-unsupported";
+        QString private_share = "private-share-supported";
+        if (!repo.account.isPro()) {
+            private_share = "private-share-unsupported";
+        } else {
+            // TODO: Sometimes we can't get the repo info, e.g. when the
+            // account the repo belongs to is not the current active account.
+            ServerRepo server_repo = RepoService::instance()->getRepo(repo.id);
+            if (server_repo.isValid() && server_repo.owner != repo.account.username) {
+                private_share = "private-share-unsupported";
+            }
+        }
+        fields << repo.id
+               << repo.name
+               << normalizedPath(repo.worktree)
+               << repoStatus(repo)
+               << file_lock
+               << private_share;
+
+        if (new_version) {
+            QString internal_link_supported = repo.account.isAtLeastVersion(6, 3, 0)
+                ? "internal-link-supported"
+                : "internal-link-unsupported";
+
+            fields << internal_link_supported;
+        }
+        infos << fields.join("\t");
+    }
+
+    return infos.join("\n");
+}
+
+QString ExtCommandsHandler::handleGetFileStatus(const QStringList& args)
+{
+    if (args.size() != 3) {
+        return "";
+    }
+
+    QString repo_id = args[0];
+    QString path_in_repo = args[1];
+    bool isdir = args[2] == "true";
+    if (repo_id.length() != 36) {
+        return "";
+    }
+
+    QString status;
+    if (ReposInfoCache::instance()->getRepoFileStatus(repo_id, path_in_repo, isdir, &status)) {
+        // qWarning("status for %s is %s", path_in_repo.toUtf8().data(), status.toUtf8().data());
+        return status;
+    }
+
+    qWarning("failed to get file status for %s", path_in_repo.toUtf8().data());
+    return "";
+}
+
+void ExtCommandsHandler::handleLockFile(const QStringList& args, bool lock)
+{
+    if (args.size() != 1) {
+        return;
+    }
+    QString path = normalizedPath(args[0]);
+    foreach (const LocalRepo& repo, listLocalRepos()) {
+        QString wt = normalizedPath(repo.worktree);
+        if (path.length() > wt.length() && path.startsWith(wt) and path.at(wt.length()) == '/') {
+            QString path_in_repo = path.mid(wt.size());
+            emit lockFile(repo.id, path_in_repo, lock);
+            break;
+        }
+    }
+}
+
+void ExtCommandsHandler::handlePrivateShare(const QStringList& args,
+                                            bool to_group)
+{
+    if (args.size() != 1) {
+        return;
+    }
+    QString path = normalizedPath(args[0]);
+    if (!QFileInfo(path).isDir()) {
+        qWarning("attempted to share %s, which is not a folder",
+                 path.toUtf8().data());
+        return;
+    }
+    foreach (const LocalRepo& repo, listLocalRepos()) {
+        QString wt = normalizedPath(repo.worktree);
+        if (path.length() > wt.length() && path.startsWith(wt) &&
+            path.at(wt.length()) == '/') {
+            QString path_in_repo = path.mid(wt.size());
+            emit privateShare(repo.id, path_in_repo, to_group);
+            break;
+        }
+    }
+}
+
+void ExtCommandsHandler::handleShowHistory(const QStringList& args)
+{
+    if (args.size() != 1) {
+        return;
+    }
+    QString path = normalizedPath(args[0]);
+    if (QFileInfo(path).isDir()) {
+        qWarning("attempted to view history of %s, which is not a regular file",
+                 path.toUtf8().data());
+        return;
+    }
+    foreach (const LocalRepo& repo, listLocalRepos()) {
+        QString wt = normalizedPath(repo.worktree);
+        if (path.length() > wt.length() && path.startsWith(wt) &&
+            path.at(wt.length()) == '/') {
+            if (repo.account.isValid()) {
+                QString path_in_repo = path.mid(wt.size());
+                QUrl url = "/repo/file_revisions/" + repo.id + "/";
+                url = ::includeQueryParams(url, {{"p", path_in_repo}});
+                emit openUrlWithAutoLogin(url);
+            }
+            break;
+        }
+    }
+}
+
+SINGLETON_IMPL(ReposInfoCache)
+
+ReposInfoCache::ReposInfoCache(QObject * parent)
+    : QObject(parent)
+{
+    cache_ts_ = 0;
+    rpc_client_ = new SeafileRpcClient();
+    connect(seafApplet->daemonManager(), SIGNAL(daemonRestarted()), this, SLOT(onDaemonRestarted()));
+}
+
+void ReposInfoCache::start()
+{
+    rpc_client_->tryConnectDaemon();
+}
+
+void ReposInfoCache::onDaemonRestarted()
+{
+    QMutexLocker lock(&rpc_client_mutex_);
+    qDebug("reviving message poller when daemon is restarted");
+    if (rpc_client_) {
+        delete rpc_client_;
+    }
+    rpc_client_ = new SeafileRpcClient();
+    rpc_client_->tryConnectDaemon();
+}
+
+
+QList<LocalRepo> ReposInfoCache::getReposInfo(quint64 ts)
+{
+    QMutexLocker lock(&rpc_client_mutex_);
+
+    // There are two levels of repos lists cache in the shell extension:
+    // 1. The extension would cache the repos list in explorer side so it
+    //    doesn't need to queries the applet repeatly in situations like
+    //    entering a folder with lots of files
+    // 2. The applet would also cache the repos list (in ReposInfoCache), this
+    //    is to reduce the overhead when different extension connections askes
+    //    for the repos list simultaneously
+
+    quint64 now = QDateTime::currentMSecsSinceEpoch();
+
+    if (cache_ts_ != 0 && cache_ts_ > ts && now - cache_ts_ < kReposInfoCacheMSecs) {
+        // qDebug("ReposInfoCache: return cached info");
+        return cached_info_;
+    }
+    // qDebug("ReposInfoCache: fetch from daemon");
+
+    std::vector<LocalRepo> repos;
+    rpc_client_->listLocalRepos(&repos);
+
+    for (size_t i = 0; i < repos.size(); i++) {
+        LocalRepo& repo = repos[i];
+        rpc_client_->getSyncStatus(repo);
+        repo.account = seafApplet->accountManager()->getAccountByRepo(repo.id, rpc_client_);
+    }
+
+    cached_info_ = QVector<LocalRepo>::fromStdVector(repos).toList();
+    cache_ts_ = QDateTime::currentMSecsSinceEpoch();
+
+    return cached_info_;
+}
+
+bool ReposInfoCache::getRepoFileStatus(const QString& repo_id,
+                                       const QString& path_in_repo,
+                                       bool isdir,
+                                       QString *status)
+{
+    QMutexLocker lock(&rpc_client_mutex_);
+    return rpc_client_->getRepoFileStatus(repo_id, path_in_repo, isdir, status) == 0;
+}
diff --git a/src/ext-handler.h b/src/ext-handler.h
new file mode 100644 (file)
index 0000000..b99efd5
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef SEAFILE_CLIENT_EXT_HANLDER_H
+#define SEAFILE_CLIENT_EXT_HANLDER_H
+
+#include <QObject>
+#include <QThread>
+#include <QMutex>
+#include <QList>
+#include <QHash>
+
+#include <windows.h>
+
+#include "utils/singleton.h"
+#include "rpc/local-repo.h"
+#include "account.h"
+
+class SeafileRpcClient;
+class ExtConnectionListenerThread;
+class ApiError;
+
+/**
+ * Handles commands from seafile shell extension
+ */
+class SeafileExtensionHandler : public QObject {
+    SINGLETON_DEFINE(SeafileExtensionHandler)
+    Q_OBJECT
+public:
+    SeafileExtensionHandler();
+    void start();
+    void stop();
+
+private slots:
+    void onShareLinkGenerated(const QString& link);
+    void onLockFileSuccess();
+    void onLockFileFailed(const ApiError& error);
+    void generateShareLink(const QString& repo_id,
+                           const QString& path_in_repo,
+                           bool is_file,
+                           bool internal);
+    void lockFile(const QString& repo_id,
+                  const QString& path_in_repo,
+                  bool lock);
+    void privateShare(const QString& repo_id,
+                      const QString& path_in_repo,
+                      bool to_group);
+    void openUrlWithAutoLogin(const QUrl& url);
+    void onGetSmartLinkSuccess(const QString& smart_link);
+    void onGetSmartLinkFailed(const ApiError& error);
+
+private:
+    ExtConnectionListenerThread *listener_thread_;
+
+    bool started_;
+};
+
+/**
+ * Creates the named pipe and listen for incoming connections in a separate
+ * thread.
+ *
+ * When a connection is accepted, create a new ExtCommandsHandler thread to
+ * serve it.
+ */
+class ExtConnectionListenerThread : public QThread {
+    Q_OBJECT
+public:
+    void run();
+
+signals:
+    void generateShareLink(const QString& repo_id,
+                           const QString& path_in_repo,
+                           bool is_file,
+                           bool internal);
+    void lockFile(const QString& repo_id,
+                  const QString& path_in_repo,
+                  bool lock);
+    void privateShare(const QString& repo_id,
+                      const QString& path_in_repo,
+                      bool to_group);
+    void openUrlWithAutoLogin(const QUrl& url);
+
+private:
+    void servePipeInNewThread(HANDLE pipe);
+};
+
+/**
+ * Serves one extension connection.
+ *
+ * It's an endless loop of "read request" -> "handle request" -> "send response".
+ */
+class ExtCommandsHandler: public QThread {
+    Q_OBJECT
+public:
+    ExtCommandsHandler(HANDLE pipe);
+    void run();
+
+signals:
+    void generateShareLink(const QString& repo_id,
+                           const QString& path_in_repo,
+                           bool is_file,
+                           bool internal);
+    void lockFile(const QString& repo_id,
+                  const QString& path_in_repo,
+                  bool lock);
+    void privateShare(const QString& repo_id,
+                      const QString& path_in_repo,
+                      bool to_group);
+    void openUrlWithAutoLogin(const QUrl& url);
+
+private:
+    HANDLE pipe_;
+
+    QList<LocalRepo> listLocalRepos(quint64 ts = 0);
+    bool readRequest(QStringList *args);
+    bool sendResponse(const QString& resp);
+
+    void handleGenShareLink(const QStringList& args, bool internal);
+    QString handleListRepos(const QStringList& args);
+    QString handleGetFileStatus(const QStringList& args);
+    void handleLockFile(const QStringList& args, bool lock);
+    void handlePrivateShare(const QStringList& args, bool to_group);
+    void handleShowHistory(const QStringList& args);
+};
+
+class ReposInfoCache : public QObject {
+    SINGLETON_DEFINE(ReposInfoCache)
+    Q_OBJECT
+public:
+    ReposInfoCache(QObject *parent=0);
+    void start();
+
+    QList<LocalRepo> getReposInfo(quint64 timestamp = 0);
+
+    bool getRepoFileStatus(const QString& repo_id,
+                           const QString& path_in_repo,
+                           bool isdir,
+                           QString *status);
+
+private slots:
+    void onDaemonRestarted();
+
+private:
+    quint64 cache_ts_;
+    QList<LocalRepo> cached_info_;
+
+    SeafileRpcClient *rpc_client_;
+    QMutex rpc_client_mutex_;
+};
+
+#endif // SEAFILE_CLIENT_EXT_HANLDER_H
diff --git a/src/filebrowser/auto-update-mgr.cpp b/src/filebrowser/auto-update-mgr.cpp
new file mode 100644 (file)
index 0000000..68dc48c
--- /dev/null
@@ -0,0 +1,399 @@
+#include <QApplication>
+#include <QDir>
+#include <QFileInfo>
+#include <QDateTime>
+#include <QTimer>
+#include <QThreadPool>
+
+#include "seafile-applet.h"
+#include "ui/tray-icon.h"
+#include "configurator.h"
+#include "account-mgr.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "utils/file-utils.h"
+#include "utils/utils.h"
+#include "utils/uninstall-helpers.h"
+#include "data-mgr.h"
+#include "tasks.h"
+#include "transfer-mgr.h"
+
+#include "auto-update-mgr.h"
+
+namespace {
+
+const char *kFileCacheTopDirName = "file-cache";
+const char *kFileCacheTempTopDirName = "file-cache-tmp";
+
+inline bool addPath(QFileSystemWatcher *watcher, const QString &file) {
+  if (watcher->files().contains(file))
+      return true;
+  bool ret = watcher->addPath(file);
+  if (!ret) {
+      qWarning("[AutoUpdateManager] failed to watch cache file %s", file.toUtf8().data());
+  }
+  return ret;
+}
+
+inline bool removePath(QFileSystemWatcher *watcher, const QString &file) {
+  if (!watcher->files().contains(file))
+      return true;
+  bool ret = watcher->removePath(file);
+  if (!ret) {
+      qWarning("[AutoUpdateManager] failed to remove watch on cache file %s", file.toUtf8().data());
+  }
+  return ret;
+}
+} // anonymous namespace
+
+SINGLETON_IMPL(AutoUpdateManager)
+
+
+AutoUpdateManager::AutoUpdateManager()
+{
+    system_shut_down_ = false;
+    connect(&watcher_, SIGNAL(fileChanged(const QString&)),
+            this, SLOT(onFileChanged(const QString&)));
+    connect(qApp, SIGNAL(aboutToQuit()),
+            this, SLOT(systemShutDown()));
+}
+
+void AutoUpdateManager::systemShutDown()
+{
+    system_shut_down_ = true;
+}
+
+void AutoUpdateManager::start()
+{
+    cleanCachedFile();
+}
+
+void AutoUpdateManager::watchCachedFile(const Account& account,
+                                        const QString& repo_id,
+                                        const QString& path)
+{
+    QString local_path = DataManager::getLocalCacheFilePath(repo_id, path);
+    qDebug("[AutoUpdateManager] watch cache file %s", local_path.toUtf8().data());
+    if (!QFileInfo(local_path).exists()) {
+        qWarning("[AutoUpdateManager] unable to watch non-existent cache file %s", local_path.toUtf8().data());
+        return;
+    }
+
+    // do we have it in deferred list ?
+    // skip if yes
+    Q_FOREACH(const WatchedFileInfo& info, deleted_files_infos_)
+    {
+        if (repo_id == info.repo_id && path == info.path_in_repo)
+            return;
+    }
+    Q_FOREACH(const WatchedFileInfo& info, watch_infos_)
+    {
+        if (repo_id == info.repo_id && path == info.path_in_repo)
+            return;
+    }
+
+    addPath(&watcher_, local_path);
+
+    QFileInfo finfo(local_path);
+    watch_infos_[local_path] =
+        WatchedFileInfo(account,
+                        repo_id,
+                        path,
+                        finfo.lastModified().toMSecsSinceEpoch(),
+                        finfo.size());
+}
+
+void AutoUpdateManager::cleanCachedFile()
+{
+    qWarning("[AutoUpdateManager] cancel all download tasks");
+    TransferManager::instance()->cancelAllDownloadTasks();
+
+    const Account cur_account = seafApplet->accountManager()->currentAccount();
+    foreach(const QString& key, watch_infos_.keys()) {
+        if (watch_infos_[key].account == cur_account)
+            watch_infos_.remove(key);
+    }
+
+    qWarning("[AutoUpdateManager] clean file caches db");
+    FileCache::instance()->cleanCurrentAccountCache();
+
+    qWarning("[AutoUpdateManager] clean file caches");
+    CachedFilesCleaner *cleaner = new CachedFilesCleaner();
+    QThreadPool::globalInstance()->start(cleaner);
+}
+
+void AutoUpdateManager::uploadFile(const QString& local_path)
+{
+    qDebug("start upload file %s", toCStr(local_path));
+    WatchedFileInfo &info = watch_infos_[local_path];
+
+    FileNetworkTask *task = seafApplet->dataManager()->createUploadTask(
+        info.repo_id, ::getParentPath(info.path_in_repo),
+        local_path, ::getBaseName(local_path), true);
+
+    ((FileUploadTask *)task)->setAcceptUserConfirmation(false);
+
+    connect(task, SIGNAL(finished(bool)),
+            this, SLOT(onUpdateTaskFinished(bool)));
+
+    qDebug("[AutoUpdateManager] start uploading new version of file %s", local_path.toUtf8().data());
+
+    info.uploading = true;
+
+    task->start();
+}
+
+void AutoUpdateManager::onFileChanged(const QString& local_path)
+{
+    qDebug("[AutoUpdateManager] detected cache file %s changed", local_path.toUtf8().data());
+    if (!watch_infos_.contains(local_path)) {
+        // filter unwanted events
+        return;
+    }
+
+    WatchedFileInfo &info = watch_infos_[local_path];
+    QFileInfo finfo(local_path);
+
+    // Download the doc file in the mac will automatically upload
+    // If the timestamp has not changed, it will not be uploaded
+    qint64 mtime = finfo.lastModified().toMSecsSinceEpoch();
+    if (mtime == info.mtime) {
+        qDebug("[AutoUpdateManager] Received a file %s upload notification, but the timestamp has not changed, "
+               "it will not upload", local_path.toUtf8().data());
+        return;
+    }
+
+#ifdef Q_OS_MAC
+    if (MacImageFilesWorkAround::instance()->isRecentOpenedImage(local_path)) {
+        qDebug("[AutoUpdateManager] skip the image file updates on mac for %s", toCStr(local_path));
+        return;
+    }
+#endif
+    removePath(&watcher_, local_path);
+    QString repo_id, path_in_repo;
+
+    if (!finfo.exists()) {
+        qDebug("[AutoUpdateManager] detected cache file %s renamed or removed", local_path.toUtf8().data());
+        WatchedFileInfo deferred_info = info;
+        removeWatch(local_path);
+        // Some application would deleted and recreate the file when saving.
+        // We work around that by double checking whether the file gets
+        // recreated after a short period
+        QTimer::singleShot(5000, this, SLOT(checkFileRecreated()));
+        deleted_files_infos_.enqueue(deferred_info);
+        return;
+    }
+
+    uploadFile(local_path);
+}
+
+void AutoUpdateManager::onUpdateTaskFinished(bool success)
+{
+    qDebug("on update task finished: %s", success ? "true" : "false");
+    if (system_shut_down_) {
+        return;
+    }
+
+    FileUploadTask *task = qobject_cast<FileUploadTask *>(sender());
+    if (task == NULL)
+        return;
+    const QString local_path = task->localFilePath();
+    const QFileInfo finfo = QFileInfo(local_path);
+    if (!finfo.exists()) {
+        //TODO: What if the delete&recreate happens just before this function is called?
+        qWarning("[AutoUpdateManager] file %s not exists anymore", toCStr(local_path));
+        return;
+    }
+
+    if (!watch_infos_.contains(local_path)) {
+        qWarning("[AutoUpdateManager] no watch info for file %s", toCStr(local_path));
+        return;
+    }
+    WatchedFileInfo& info = watch_infos_[local_path];
+    info.uploading = false;
+
+    if (success) {
+        qDebug("[AutoUpdateManager] uploaded new version of file %s", local_path.toUtf8().data());
+        info.mtime = finfo.lastModified().toMSecsSinceEpoch();
+        info.fsize = finfo.size();
+        seafApplet->trayIcon()->showMessage(tr("Upload Success"),
+                                            tr("File \"%1\"\nuploaded successfully.").arg(finfo.fileName()),
+                                            task->repoId());
+
+        // This would also set the "uploading" and "num_upload_errors" column to 0.
+        FileCache::instance()->saveCachedFileId(task->repoId(),
+                                                info.path_in_repo,
+                                                task->account().getSignature(),
+                                                task->oid(),
+                                                task->localFilePath());
+        emit fileUpdated(task->repoId(), task->path());
+    } else {
+        qWarning("[AutoUpdateManager] failed to upload new version of file %s: %s",
+                 toCStr(local_path),
+                 toCStr(task->errorString()));
+        QString error_msg;
+        if (task->httpErrorCode() == 403) {
+            error_msg = tr("Permission Error!");
+        } else if (task->httpErrorCode() == 401) {
+            error_msg = tr("Authorization expired");
+        } else if (task->httpErrorCode() == 441) {
+            error_msg = tr("File does not exist");
+        } else {
+            error_msg = task->errorString();
+        }
+
+        QString name = ::getBaseName(local_path);
+        DirentsCache::ReturnEntry retval = DirentsCache::instance()->getCachedDirents(info.repo_id, task->path());
+        QList<SeafDirent> *l = retval.second;
+        QString msg = tr("File \"%1\"\nfailed to upload.").arg(QFileInfo(local_path).fileName());
+        if (l != NULL) {
+            foreach (const SeafDirent dirent, *l) {
+                if (dirent.name == name) {
+                    if (dirent.is_locked) {
+                        msg = tr("The file is locked by %1, "
+                                 "please try again later").arg(dirent.getLockOwnerDisplayString());
+                    }
+                }
+            }
+        }
+        seafApplet->trayIcon()->showMessage(tr("Upload Failure: %1").arg(error_msg),
+                                            msg,
+                                            task->repoId());
+    }
+
+    addPath(&watcher_, local_path);
+}
+
+void AutoUpdateManager::removeWatch(const QString& local_path)
+{
+    watch_infos_.remove(local_path);
+    removePath(&watcher_, local_path);
+}
+
+void AutoUpdateManager::checkFileRecreated()
+{
+    if (deleted_files_infos_.isEmpty()) {
+        // impossible
+        return;
+    }
+
+    const WatchedFileInfo info = deleted_files_infos_.dequeue();
+    const QString path = DataManager::getLocalCacheFilePath(info.repo_id, info.path_in_repo);
+    if (QFileInfo(path).exists()) {
+        qDebug("[AutoUpdateManager] detected recreated file %s", path.toUtf8().data());
+        addPath(&watcher_, path);
+        watch_infos_[path] = info;
+        // Some applications like MSOffice would remove the original file and
+        // recreate it when the user modifies the file.
+        onFileChanged(path);
+    }
+}
+
+QHash<QString, AutoUpdateManager::FileStatus>
+AutoUpdateManager::getFileStatusForDirectory(const QString &account_sig,
+                                             const QString &repo_id,
+                                             const QString &parent_dir,
+                                             const QList<SeafDirent>& dirents)
+{
+    QHash<QString, SeafDirent> dirents_map;
+    foreach(const SeafDirent& d, dirents) {
+        if (d.isFile()) {
+            dirents_map[d.name] = d;
+        }
+    }
+
+    QHash<QString, FileStatus> ret;
+    QList<FileCache::CacheEntry> caches =
+        FileCache::instance()->getCachedFilesForDirectory(account_sig, repo_id, parent_dir);
+    if (caches.empty()) {
+        // qDebug("no cached files for dir %s\n", toCStr(parent_dir));
+    }
+    foreach(const FileCache::CacheEntry& entry, caches) {
+        // qDebug("found cache entry: %s\n", entry.path.toUtf8().data());
+
+        QString local_file_path = DataManager::getLocalCacheFilePath(entry.repo_id, entry.path);
+        const QString& file = ::getBaseName(entry.path);
+        bool is_uploading = watch_infos_.contains(local_file_path) && watch_infos_[local_file_path].uploading;
+
+        if (!dirents_map.contains(file)) {
+            // qDebug("cached files no longer exists: %s\n", entry.path.toUtf8().data());
+            continue;
+        }
+
+        const SeafDirent& d = dirents_map[file];
+        if (d.id != entry.file_id) {
+            // qDebug("cached file is a stale version: %s\n", entry.path.toUtf8().data());
+            ret[file] = is_uploading ? UPLOADING : NOT_SYNCED;
+            continue;
+        }
+
+        QFileInfo finfo(local_file_path);
+
+        qint64 mtime = finfo.lastModified().toMSecsSinceEpoch();
+        bool consistent = mtime == entry.seafile_mtime && finfo.size() == entry.seafile_size;
+        if (consistent) {
+            ret[file] = is_uploading ? UPLOADING: SYNCED;
+        } else {
+            ret[file] = is_uploading ? UPLOADING : NOT_SYNCED;
+        }
+        qDebug("is_uploading %s, local_file_path is %s", is_uploading ? "true" : "false", toCStr(local_file_path));
+    }
+    return ret;
+}
+
+#ifdef Q_OS_MAC
+SINGLETON_IMPL(MacImageFilesWorkAround)
+
+MacImageFilesWorkAround::MacImageFilesWorkAround()
+{
+}
+
+void MacImageFilesWorkAround::fileOpened(const QString& path)
+{
+    QString mimetype = ::mimeTypeFromFileName(path);
+    if (mimetype.startsWith("image") || mimetype == "application/pdf") {
+        images_[path] = QDateTime::currentMSecsSinceEpoch();
+    }
+}
+
+bool MacImageFilesWorkAround::isRecentOpenedImage(const QString& path)
+{
+    qint64 ts = images_.value(path, 0);
+    if (QDateTime::currentMSecsSinceEpoch() < ts + 1000 * 10) {
+        return true;
+    } else {
+        return false;
+    }
+}
+#endif
+
+CachedFilesCleaner::CachedFilesCleaner()
+{
+}
+
+void CachedFilesCleaner::run()
+{
+    QString file_cache_dir = pathJoin(seafApplet->configurator()->seafileDir(),
+                               kFileCacheTopDirName);
+    QString file_cache_tmp_dir = pathJoin(seafApplet->configurator()->seafileDir(),
+                                   kFileCacheTempTopDirName);
+
+    qDebug("[AutoUpdateManager] removing cached files");
+    if (QDir(file_cache_tmp_dir).exists()) {
+        delete_dir_recursively(file_cache_tmp_dir);
+    }
+    if (QDir(file_cache_dir).exists()) {
+        QDir().rename(file_cache_dir, file_cache_tmp_dir);
+        delete_dir_recursively(file_cache_tmp_dir);
+    }
+}
+
+void AutoUpdateManager::dumpCacheStatus()
+{
+    printf ("---------------BEGIN CACHE INFO -------------\n");
+    foreach(const QString& key, watch_infos_.keys()) {
+        WatchedFileInfo& info = watch_infos_[key];
+        printf ("%s mtime = %lld, fsize = %lld, uploading = %s\n", toCStr(info.path_in_repo), info.mtime, info.fsize, info.uploading ? "true" : "false");
+    }
+    printf ("---------------END CACHE INFO -------------\n");
+}
diff --git a/src/filebrowser/auto-update-mgr.h b/src/filebrowser/auto-update-mgr.h
new file mode 100644 (file)
index 0000000..cbcd829
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_AUTO_UPDATE_MANAGER_H
+#define SEAFILE_CLIENT_FILE_BROWSER_AUTO_UPDATE_MANAGER_H
+
+#include <QFileSystemWatcher>
+#include <QHash>
+#include <QQueue>
+#include <QRunnable>
+#include <QScopedPointer>
+
+#include "utils/singleton.h"
+#include "account.h"
+#include "data-cache.h"
+#include "data-mgr.h"
+
+class AutoUpdateManager : public QObject {
+    SINGLETON_DEFINE(AutoUpdateManager)
+    Q_OBJECT
+
+public:
+    void start();
+    void removeWatch(const QString& path);
+    void watchCachedFile(const Account& account,
+                         const QString& repo_id,
+                         const QString& path);
+
+    enum FileStatus {
+        // Local cache is consistent with the version on the server
+        SYNCED = 0,
+        // The file is being auto-uploaded
+        UPLOADING,
+        // Not synced and also not uploading, this happens e.g. when the upload
+        // request failed
+        NOT_SYNCED,
+    };
+
+    QHash<QString, FileStatus> getFileStatusForDirectory(
+        const QString &account_sig,
+        const QString &repo_id,
+        const QString &path,
+        const QList<SeafDirent>& dirents);
+    void cleanCachedFile();
+    void uploadFile(const QString& local_path);
+    void dumpCacheStatus();
+
+signals:
+    void fileUpdated(const QString& repo_id, const QString& path);
+
+private slots:
+    void onFileChanged(const QString& path);
+    void onUpdateTaskFinished(bool success);
+    void checkFileRecreated();
+    void systemShutDown();
+
+private:
+    AutoUpdateManager();
+
+    QFileSystemWatcher watcher_;
+
+    struct WatchedFileInfo {
+        Account account;
+        QString repo_id;
+        QString path_in_repo;
+        qint64 mtime;
+        qint64 fsize;
+
+        bool uploading = false;
+
+        WatchedFileInfo() {}
+        WatchedFileInfo(const Account& account,
+                        const QString& repo_id,
+                        const QString& path_in_repo,
+                        qint64 mtime,
+                        qint64 fsize)
+            : account(account),
+              repo_id(repo_id),
+              path_in_repo(path_in_repo),
+              mtime(mtime),
+              fsize(fsize)
+              {}
+    };
+
+    QHash<QString, WatchedFileInfo> watch_infos_;
+
+    QQueue<WatchedFileInfo> deleted_files_infos_;
+
+    bool system_shut_down_;
+};
+
+#ifdef Q_OS_MAC
+/**
+ * On MacOSX, when open an image file in Preview app, a file modificatin event
+ * would be triggered, but the file is not modified. We need to work around
+ * this so the auto update manager would not be fooled by this false signal.
+ */
+class MacImageFilesWorkAround {
+    SINGLETON_DEFINE(MacImageFilesWorkAround)
+public:
+    MacImageFilesWorkAround();
+    bool isRecentOpenedImage(const QString& path);
+    void fileOpened(const QString& path);
+
+private:
+    QHash<QString, qint64> images_;
+};
+#endif // Q_OS_MAC
+
+class CachedFilesCleaner : public QObject, public QRunnable {
+    Q_OBJECT
+public:
+    CachedFilesCleaner();
+    void run();
+    bool autoDelete() {
+        return true;
+    }
+};
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_AUTO_UPDATE_MANAGER_H
diff --git a/src/filebrowser/data-cache.cpp b/src/filebrowser/data-cache.cpp
new file mode 100644 (file)
index 0000000..15446ce
--- /dev/null
@@ -0,0 +1,293 @@
+#include <QDir>
+#include <sqlite3.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <QDateTime>
+#include <QCache>
+
+#include "utils/file-utils.h"
+#include "utils/utils.h"
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "data-cache.h"
+#include "data-mgr.h"
+#include "account-mgr.h"
+
+namespace {
+
+const int kDirentsCacheExpireTime = 60 * 1000;
+
+void filecache_entry_from_sqlite3_result(sqlite3_stmt *stmt, FileCache::CacheEntry* entry)
+{
+    entry->repo_id = (const char *)sqlite3_column_text (stmt, 0);
+    entry->path = QString::fromUtf8((const char *)sqlite3_column_text (stmt, 1));
+    entry->account_sig = (const char *)sqlite3_column_text (stmt, 2);
+    entry->file_id = (const char *)sqlite3_column_text (stmt, 3);
+    entry->seafile_mtime = sqlite3_column_int64 (stmt, 4);
+    entry->seafile_size = sqlite3_column_int64 (stmt, 5);
+}
+
+} // namespace
+
+SINGLETON_IMPL(DirentsCache)
+DirentsCache::DirentsCache()
+{
+    cache_ = new QCache<QString, CacheEntry>;
+}
+DirentsCache::~DirentsCache()
+{
+    delete cache_;
+}
+
+DirentsCache::ReturnEntry
+DirentsCache::getCachedDirents(const QString& repo_id,
+                               const QString& path)
+{
+    QString cache_key = repo_id + path;
+    CacheEntry *e = cache_->object(cache_key);
+    if (e != NULL) {
+        qint64 now = QDateTime::currentMSecsSinceEpoch();
+        if (now < e->timestamp + kDirentsCacheExpireTime) {
+            return ReturnEntry(e->current_readonly, &(e->dirents));
+        }
+    }
+
+    return ReturnEntry(false, NULL);
+}
+
+void DirentsCache::expireCachedDirents(const QString& repo_id, const QString& path)
+{
+    cache_->remove(repo_id + path);
+}
+
+void DirentsCache::saveCachedDirents(const QString& repo_id,
+                                     const QString& path,
+                                     bool current_readonly,
+                                     const QList<SeafDirent>& dirents)
+{
+    CacheEntry *val = new CacheEntry;
+    val->timestamp = QDateTime::currentMSecsSinceEpoch();
+    val->current_readonly = current_readonly;
+    val->dirents = dirents;
+    QString cache_key = repo_id + path;
+    cache_->insert(cache_key, val);
+}
+
+#if 0
+SINGLETON_IMPL(FileCache)
+FileCache::FileCache()
+{
+    cache_ = new QHash<QString, CacheEntry>;
+}
+
+FileCache::~FileCache()
+{
+    delete cache_;
+}
+
+QString FileCache::getCachedFileId(const QString& repo_id,
+                                     const QString& path)
+{
+    return getCacheEntry(repo_id, path).file_id;
+}
+
+FileCache::CacheEntry FileCache::getCacheEntry(const QString& repo_id,
+                                                   const QString& path)
+{
+    QString cache_key = repo_id + path;
+
+    return cache_->value(cache_key);
+}
+
+void FileCache::saveCachedFileId(const QString& repo_id,
+                                   const QString& path,
+                                   const QString& file_id,
+                                   const QString& account_sig)
+{
+    CacheEntry val;
+    QString cache_key = repo_id + path;
+
+    val.repo_id = repo_id;
+    val.path = path;
+    val.file_id = file_id;
+    val.account_sig = account_sig;
+
+    cache_->insert(cache_key, val);
+}
+
+QList<FileCache::CacheEntry> FileCache::getAllCachedFiles()
+{
+    return cache_->values();
+}
+
+void FileCache::cleanCurrentAccountCache()
+{
+    const Account cur_account = seafApplet->accountManager()->currentAccount();
+    foreach(const QString& key, cache_->keys()) {
+        const Account account = seafApplet->accountManager()
+                                ->getAccountBySignature(cache_->value(key).account_sig);
+        if (account == cur_account)
+            cache_->remove(key);
+    }
+}
+#endif
+
+SINGLETON_IMPL(FileCache)
+FileCache::FileCache()
+{
+    db_ = NULL;
+}
+
+FileCache::~FileCache()
+{
+    if (db_ != NULL)
+        sqlite3_close(db_);
+}
+
+void FileCache::start()
+{
+    const char *errmsg;
+    const char *sql;
+    sqlite3 *db;
+
+    QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("autoupdate-cache.db");
+    if (sqlite3_open (toCStr(db_path), &db)) {
+        errmsg = sqlite3_errmsg (db);
+        qDebug("failed to open file cache database %s: %s",
+               toCStr(db_path), errmsg ? errmsg : "no error given");
+
+        seafApplet->errorAndExit(QObject::tr("failed to open file cache database"));
+        return;
+    }
+
+    // Drop the old table.
+    // XX(lins05): This is not ideal. Should we invent a table schema upgrade mechanism?
+    sql = "DROP TABLE IF EXISTS FileCache;";
+    sqlite_query_exec (db, sql);
+    sql = "DROP TABLE IF EXISTS FileCacheV1;";
+    sqlite_query_exec (db, sql);
+
+    sql = "CREATE TABLE IF NOT EXISTS FileCacheV2 ("
+        "     repo_id VARCHAR(36), "
+        "     path VARCHAR(4096), "
+        "     account_sig VARCHAR(40) NOT NULL, "
+        "     file_id VARCHAR(40) NOT NULL, "
+        "     seafile_mtime integer NOT NULL, "
+        "     seafile_size integer NOT NULL, "
+        "     PRIMARY KEY (repo_id, path))";
+    sqlite_query_exec (db, sql);
+
+    db_ = db;
+}
+
+bool FileCache::getCacheEntryCB(sqlite3_stmt *stmt, void *data)
+{
+    CacheEntry *entry = (CacheEntry *)data;
+    filecache_entry_from_sqlite3_result(stmt, entry);
+    return true;
+}
+
+bool FileCache::getCacheEntry(const QString& repo_id,
+                              const QString& path,
+                              FileCache::CacheEntry *entry)
+{
+    char *zql = sqlite3_mprintf("SELECT *"
+                                "  FROM FileCacheV2"
+                                " WHERE repo_id = %Q"
+                                "   AND path = %Q",
+                                repo_id.toUtf8().data(), path.toUtf8().data());
+    bool ret = sqlite_foreach_selected_row(db_, zql, getCacheEntryCB, entry) > 0;
+    sqlite3_free(zql);
+    return ret;
+}
+
+void FileCache::saveCachedFileId(const QString& repo_id,
+                                 const QString& path,
+                                 const QString& account_sig,
+                                 const QString& file_id,
+                                 const QString& local_file_path)
+{
+    QFileInfo finfo (local_file_path);
+    qint64 mtime = finfo.lastModified().toMSecsSinceEpoch();
+    qint64 fsize = finfo.size();
+    char *zql = sqlite3_mprintf("REPLACE INTO FileCacheV2( "
+                                "repo_id, path, account_sig, file_id, "
+                                "seafile_mtime, seafile_size "
+                                ") VALUES (%Q, %Q, %Q, %Q, %lld, %lld)",
+                                toCStr(repo_id),
+                                toCStr(path),
+                                toCStr(account_sig),
+                                toCStr(file_id),
+                                mtime,
+                                fsize);
+    sqlite_query_exec(db_, zql);
+    sqlite3_free(zql);
+}
+
+bool FileCache::collectCachedFile(sqlite3_stmt *stmt, void *data)
+{
+    QList<CacheEntry> *list = (QList<CacheEntry> *)data;
+
+    CacheEntry entry;
+    filecache_entry_from_sqlite3_result(stmt, &entry);
+    list->append(entry);
+    return true;
+}
+
+QList<FileCache::CacheEntry> FileCache::getAllCachedFiles()
+{
+    const char* sql = "SELECT * FROM FileCacheV2";
+    QList<CacheEntry> list;
+    sqlite_foreach_selected_row(db_, sql, collectCachedFile, &list);
+    return list;
+}
+
+void FileCache::cleanCurrentAccountCache()
+{
+    const Account account = seafApplet->accountManager()->currentAccount();
+    if (!account.isValid()) {
+        return;
+    }
+    char *zql = sqlite3_mprintf(
+        "DELETE FROM FileCacheV2 where account_sig = %Q",
+        toCStr(account.getSignature()));
+    sqlite_query_exec(db_, zql);
+    sqlite3_free(zql);
+}
+
+QList<FileCache::CacheEntry> FileCache::getCachedFilesForDirectory(const QString& account_sig,
+                                                                   const QString& repo_id,
+                                                                   const QString& parent_dir_in)
+{
+    QString parent_dir = parent_dir_in;
+    // Strip the trailing slash
+    if (parent_dir.length() > 1 && parent_dir.endsWith("/")) {
+        parent_dir = parent_dir.left(parent_dir.length() - 1);
+    }
+
+    QList<CacheEntry> entries;
+    char* sql = sqlite3_mprintf("SELECT * FROM FileCacheV2 "
+                                "WHERE repo_id = %Q "
+                                "  AND path like %Q "
+                                "  AND account_sig = %Q; ",
+                                toCStr(repo_id),
+                                toCStr(QString("%1%").arg(parent_dir == "/" ? parent_dir : parent_dir + "/")),
+                                toCStr(account_sig));
+
+    sqlite_foreach_selected_row(db_, sql, collectCachedFile, &entries);
+
+    // Even if we filtered the path in the above sql query, the returned entries
+    // may still belong to subdirectory of "parent_dir" instead of parent_dir
+    // itself. So we need to fitler again.
+    QList<CacheEntry> ret;
+    foreach(const CacheEntry& entry, entries) {
+        if (::getParentPath(entry.path) == parent_dir) {
+            QString localpath = DataManager::instance()->getLocalCacheFilePath(entry.repo_id, entry.path);
+            if (QFileInfo(localpath).exists()) {
+                ret.append(entry);
+            }
+        }
+    }
+    return ret;
+}
diff --git a/src/filebrowser/data-cache.h b/src/filebrowser/data-cache.h
new file mode 100644 (file)
index 0000000..0e44873
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_DATA_CACHE_H
+#define SEAFILE_CLIENT_FILE_BROWSER_DATA_CACHE_H
+
+#include <QList>
+#include <utility>
+
+#include "seaf-dirent.h"
+#include "utils/singleton.h"
+
+template<typename Key, typename T> class QCache;
+
+struct sqlite3;
+struct sqlite3_stmt;
+
+/**
+ * Cache dirents by (repo_id + path, dirents) in memory
+ */
+class DirentsCache {
+    SINGLETON_DEFINE(DirentsCache)
+public:
+    typedef std::pair<bool ,QList<SeafDirent>*> ReturnEntry;
+    ReturnEntry getCachedDirents(const QString& repo_id,
+                                 const QString& path);
+
+    void expireCachedDirents(const QString& repo_id, const QString& path);
+
+    void saveCachedDirents(const QString& repo_id,
+                           const QString& path,
+                           bool current_readonly,
+                           const QList<SeafDirent>& dirents);
+
+private:
+    DirentsCache();
+    ~DirentsCache();
+    struct CacheEntry {
+        qint64 timestamp;
+        bool current_readonly;
+        QList<SeafDirent> dirents;
+    };
+
+    QCache<QString, CacheEntry> *cache_;
+};
+
+#if 0
+/**
+ * Record the file id of downloaded files.
+ * The schema is (repo_id, path, downloaded_file_id)
+ */
+class FileCache {
+    SINGLETON_DEFINE(FileCache)
+public:
+    struct CacheEntry {
+        QString repo_id;
+        QString path;
+        QString file_id;
+        QString account_sig;
+    };
+
+
+    QString getCachedFileId(const QString& repo_id,
+                            const QString& path);
+    CacheEntry getCacheEntry(const QString& repo_id,
+                             const QString& path);
+    void saveCachedFileId(const QString& repo_id,
+                          const QString& path,
+                          const QString& file_id,
+                          const QString& account_sig);
+
+    QList<CacheEntry> getAllCachedFiles();
+    void cleanCurrentAccountCache();
+
+private:
+    FileCache();
+    ~FileCache();
+
+    QHash<QString, CacheEntry> *cache_;
+};
+#endif
+
+/**
+ * Record the file id of downloaded files.
+ */
+class FileCache {
+    SINGLETON_DEFINE(FileCache)
+public:
+    struct CacheEntry {
+        QString repo_id;
+        QString path;
+        QString account_sig;
+        QString file_id;
+        qint64  seafile_mtime;
+        qint64  seafile_size;
+    };
+
+    void start();
+
+    bool getCacheEntry(const QString& repo_id,
+                       const QString& path,
+                       CacheEntry *entry);
+    void saveCachedFileId(const QString& repo_id,
+                          const QString& path,
+                          const QString& file_id,
+                          const QString& account_sig,
+                          const QString& local_file_path);
+
+    QList<CacheEntry> getCachedFilesForDirectory(const QString& account_sig,
+                                                 const QString& repo_id,
+                                                 const QString& parent_dir);
+
+    QList<CacheEntry> getAllCachedFiles();
+    void cleanCurrentAccountCache();
+
+private:
+    FileCache();
+    ~FileCache();
+    static bool getCacheEntryCB(sqlite3_stmt *stmt, void *data);
+    static bool collectCachedFile(sqlite3_stmt *stmt, void *data);
+
+    sqlite3 *db_;
+};
+
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_DATA_CACHE_H
diff --git a/src/filebrowser/data-mgr.cpp b/src/filebrowser/data-mgr.cpp
new file mode 100644 (file)
index 0000000..92270ea
--- /dev/null
@@ -0,0 +1,549 @@
+#include <errno.h>
+#include <cstdio>
+#include <sqlite3.h>
+
+#include <QDir>
+#include <QDateTime>
+
+#include "utils/file-utils.h"
+#include "utils/utils.h"
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "auto-update-mgr.h"
+#include "api/requests.h"
+#include "repo-service.h"
+#include "account-mgr.h"
+
+#include "filebrowser/file-browser-requests.h"
+#include "filebrowser/tasks.h"
+#include "filebrowser/transfer-mgr.h"
+#include "filebrowser/data-cache.h"
+#include "filebrowser/data-mgr.h"
+
+namespace {
+
+const char *kFileCacheTopDirName = "file-cache";
+const int kPasswordCacheExpirationMSecs = 30 * 60 * 1000;
+
+} // namespace
+
+/**
+ * Cache loaded dirents. But default cache expires after 1 minute.
+ */
+
+SINGLETON_IMPL(DataManager)
+
+DataManager::DataManager()
+    : filecache_(FileCache::instance()),
+      dirents_cache_(DirentsCache::instance())
+{
+}
+
+DataManager::~DataManager()
+{
+    emit aboutToDestroy();
+    Q_FOREACH(SeafileApiRequest *req, reqs_)
+    {
+        req->deleteLater();
+    }
+}
+
+void DataManager::start()
+{
+    account_ = seafApplet->accountManager()->currentAccount();
+
+    connect(seafApplet->accountManager(), SIGNAL(accountsChanged()),
+            this, SLOT(onAccountChanged()));
+}
+
+bool DataManager::getDirents(const QString& repo_id,
+                             const QString& path,
+                             QList<SeafDirent> *dirents,
+                             bool *current_readonly)
+{
+    DirentsCache::ReturnEntry retval = dirents_cache_->getCachedDirents(repo_id, path);
+    QList<SeafDirent> *l = retval.second;
+    if (l != NULL) {
+        dirents->append(*l);
+        *current_readonly = retval.first;
+        return true;
+    } else {
+        return false;
+    }
+}
+
+void DataManager::getDirentsFromServer(const QString& repo_id,
+                                       const QString& path)
+{
+    GetDirentsRequest *get_dirents_req = new GetDirentsRequest(account_, repo_id, path);
+    connect(get_dirents_req, SIGNAL(success(bool, const QList<SeafDirent>&, const QString&)),
+            this, SLOT(onGetDirentsSuccess(bool, const QList<SeafDirent>&, const QString&)));
+    connect(get_dirents_req, SIGNAL(failed(const ApiError&, const QString&)),
+            this, SIGNAL(getDirentsFailed(const ApiError&, const QString&)));
+    get_dirents_req->send();
+    reqs_.push_back(get_dirents_req);
+}
+
+void DataManager::createDirectory(const QString &repo_id,
+                                  const QString &path)
+{
+    CreateDirectoryRequest *req = new CreateDirectoryRequest(account_, repo_id, path);
+    connect(req, SIGNAL(success(const QString&)),
+            SLOT(onCreateDirectorySuccess(const QString&)));
+
+    connect(req, SIGNAL(failed(const ApiError&)),
+            SIGNAL(createDirectoryFailed(const ApiError&)));
+
+    req->send();
+    reqs_.push_back(req);
+}
+
+void DataManager::lockFile(const QString &repo_id,
+                           const QString &path,
+                           bool lock)
+{
+    LockFileRequest *req = new LockFileRequest(account_, repo_id, path, lock);
+    connect(req, SIGNAL(success(const QString&)),
+            SLOT(onLockFileSuccess(const QString&)));
+
+    connect(req, SIGNAL(failed(const ApiError&)),
+            SIGNAL(lockFileFailed(const ApiError&)));
+
+    req->send();
+    reqs_.push_back(req);
+}
+
+void DataManager::renameDirent(const QString &repo_id,
+                               const QString &path,
+                               const QString &new_path,
+                               bool is_file)
+{
+    RenameDirentRequest *req = new RenameDirentRequest(account_, repo_id, path,
+                                                       new_path, is_file);
+    connect(req, SIGNAL(success(const QString&)),
+            SLOT(onRenameDirentSuccess(const QString&)));
+
+    connect(req, SIGNAL(failed(const ApiError&)),
+            SIGNAL(renameDirentFailed(const ApiError&)));
+    req->send();
+    reqs_.push_back(req);
+}
+
+
+void DataManager::removeDirent(const QString &repo_id,
+                               const QString &path,
+                               bool is_file)
+{
+    RemoveDirentRequest *req = new RemoveDirentRequest(account_, repo_id, path,
+                                                       is_file);
+    connect(req, SIGNAL(success(const QString&)),
+            SLOT(onRemoveDirentSuccess(const QString&)));
+
+    connect(req, SIGNAL(failed(const ApiError&)),
+            SIGNAL(removeDirentFailed(const ApiError&)));
+    req->send();
+    reqs_.push_back(req);
+}
+
+void DataManager::removeDirents(const QString &repo_id,
+                                const QString &parent_path,
+                                const QStringList &filenames)
+{
+    RemoveDirentsRequest *req = new RemoveDirentsRequest(account_, repo_id, parent_path,
+                                                         filenames);
+    connect(req, SIGNAL(success(const QString&)),
+            SLOT(onRemoveDirentsSuccess(const QString&)));
+
+    connect(req, SIGNAL(failed(const ApiError&)),
+            SIGNAL(removeDirentsFailed(const ApiError&)));
+    req->send();
+    reqs_.push_back(req);
+}
+
+void DataManager::shareDirent(const QString &repo_id,
+                              const QString &path,
+                              bool is_file)
+{
+    GetSharedLinkRequest *req = new GetSharedLinkRequest(account_, repo_id,
+                                                         path, is_file);
+    connect(req, SIGNAL(success(const QString&, const QString&)),
+            SIGNAL(shareDirentSuccess(const QString&, const QString&)));
+
+    connect(req, SIGNAL(failed(const ApiError&)),
+            SIGNAL(shareDirentFailed(const ApiError&)));
+    reqs_.push_back(req);
+    req->send();
+}
+
+void DataManager::copyDirents(const QString &repo_id,
+                              const QString &dir_path,
+                              const QStringList &file_names,
+                              const QString &dst_repo_id,
+                              const QString &dst_dir_path)
+{
+    CopyMultipleFilesRequest *req =
+      new CopyMultipleFilesRequest(account_, repo_id, dir_path, file_names,
+                                   dst_repo_id,
+                                   dst_dir_path);
+    connect(req, SIGNAL(success(const QString&)),
+            SLOT(onCopyDirentsSuccess(const QString&)));
+
+    connect(req, SIGNAL(failed(const ApiError&)),
+            SIGNAL(copyDirentsFailed(const ApiError&)));
+    reqs_.push_back(req);
+    req->send();
+}
+
+void DataManager::moveDirents(const QString &repo_id,
+                              const QString &dir_path,
+                              const QStringList &file_names,
+                              const QString &dst_repo_id,
+                              const QString &dst_dir_path)
+{
+    MoveMultipleFilesRequest *req =
+      new MoveMultipleFilesRequest(account_, repo_id, dir_path, file_names,
+                                   dst_repo_id,
+                                   dst_dir_path);
+    connect(req, SIGNAL(success(const QString&)),
+            SLOT(onMoveDirentsSuccess(const QString&)));
+
+    connect(req, SIGNAL(failed(const ApiError&)),
+            SIGNAL(moveDirentsFailed(const ApiError&)));
+    reqs_.push_back(req);
+    req->send();
+}
+
+void DataManager::onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent> &dirents, const QString& repo_id)
+{
+    GetDirentsRequest *get_dirents_req =  qobject_cast<GetDirentsRequest *>(sender());
+    dirents_cache_->saveCachedDirents(get_dirents_req->repoId(),
+                                      get_dirents_req->path(),
+                                      current_readonly,
+                                      dirents);
+
+    emit getDirentsSuccess(current_readonly, dirents, repo_id);
+}
+
+void DataManager::onCreateDirectorySuccess(const QString& repo_id)
+{
+    CreateDirectoryRequest *req = qobject_cast<CreateDirectoryRequest*>(sender());
+
+    if(req == NULL)
+        return;
+
+    removeDirentsCache(req->repoId(), req->path(), false);
+    emit createDirectorySuccess(req->path(), repo_id);
+}
+
+void DataManager::onLockFileSuccess(const QString& repo_id)
+{
+    LockFileRequest *req = qobject_cast<LockFileRequest *>(sender());
+    if (!req)
+        return;
+
+    removeDirentsCache(req->repoId(), req->path(), false);
+    seafApplet->rpcClient()->markFileLockState(req->repoId(), req->path(), req->lock());
+    emit lockFileSuccess(req->path(), req->lock(), repo_id);
+}
+
+void DataManager::onRenameDirentSuccess(const QString& repo_id)
+{
+    RenameDirentRequest *req = qobject_cast<RenameDirentRequest*>(sender());
+
+    if(req == NULL)
+        return;
+
+    removeDirentsCache(req->repoId(), req->path(), req->isFile());
+    emit renameDirentSuccess(req->path(), req->newName(), repo_id);
+}
+
+void DataManager::onRemoveDirentSuccess(const QString& repo_id)
+{
+    RemoveDirentRequest *req = qobject_cast<RemoveDirentRequest*>(sender());
+
+    if(req == NULL)
+        return;
+
+    removeDirentsCache(req->repoId(), req->path(), req->isFile());
+    emit removeDirentSuccess(req->path(), repo_id);
+}
+
+void DataManager::onRemoveDirentsSuccess(const QString& repo_id)
+{
+    RemoveDirentsRequest *req = qobject_cast<RemoveDirentsRequest*>(sender());
+
+    if(req == NULL)
+        return;
+
+    removeDirentsCache(req->repoId(), req->parentPath(), false);
+    emit removeDirentsSuccess(req->parentPath(), req->filenames(), repo_id);
+}
+
+void DataManager::onCopyDirentsSuccess(const QString& dst_repo_id)
+{
+    emit copyDirentsSuccess(dst_repo_id);
+}
+
+void DataManager::onMoveDirentsSuccess(const QString& dst_repo_id)
+{
+    MoveMultipleFilesRequest *req = qobject_cast<MoveMultipleFilesRequest*>(sender());
+    dirents_cache_->expireCachedDirents(req->srcRepoId(), req->srcPath());
+
+    emit moveDirentsSuccess(dst_repo_id);
+}
+
+void DataManager::removeDirentsCache(const QString& repo_id,
+                                     const QString& path,
+                                     bool is_file)
+{
+    // expire its parent's cache
+    dirents_cache_->expireCachedDirents(repo_id, ::getParentPath(path));
+    // if the object is a folder, then expire its self cache
+    if (!is_file)
+        dirents_cache_->expireCachedDirents(repo_id, path);
+}
+
+
+QString DataManager::getLocalCachedFile(const QString& repo_id,
+                                        const QString& fpath,
+                                        const QString& file_id)
+{
+    QString local_file_path = getLocalCacheFilePath(repo_id, fpath);
+    QFileInfo finfo(local_file_path);
+    if (!finfo.exists()) {
+        qWarning ("No cache file for %s\n", toCStr(fpath));
+        return "";
+    }
+
+    FileCache::CacheEntry entry;
+    if (!filecache_->getCacheEntry(repo_id, fpath, &entry)) {
+        qWarning ("No cache db entry for %s\n", toCStr(fpath));
+        return "";
+    }
+
+    if (entry.file_id == file_id) {
+        qWarning ("cache file id matched for %s: %s\n", toCStr(fpath), toCStr(file_id));
+        return local_file_path;
+    } else {
+        // The file is updated on server
+        qint64 mtime = finfo.lastModified().toMSecsSinceEpoch();
+        bool use_cached = false;
+        if (mtime != entry.seafile_mtime) {
+            qWarning(
+                "cache file is updated locally (mtime changed from %lld to "
+                "%lld), use it: %s\n",
+                entry.seafile_mtime,
+                mtime,
+                toCStr(fpath));
+            use_cached = true;
+        } else if (finfo.size() != entry.seafile_size) {
+            qWarning(
+                "cache file is updated locally (size changed from %lld to "
+                "%lld), use it: %s\n",
+                entry.seafile_size,
+                finfo.size(),
+                toCStr(fpath));
+            use_cached = true;
+        }
+
+        if (use_cached) {
+            // If the file is also updated locally, open it directly
+            return local_file_path;
+        } else {
+            qWarning ("cache file is outdated, download newer version: %s\n", toCStr(fpath));
+            // Otherwise the newer version would be downloaded
+            return "";
+        }
+    }
+}
+
+FileDownloadTask* DataManager::createDownloadTask(const QString& repo_id,
+                                                  const QString& path)
+{
+    QString local_path = getLocalCacheFilePath(repo_id, path);
+    FileDownloadTask* task = TransferManager::instance()->addDownloadTask(
+        account_, repo_id, path, local_path);
+    connect(task, SIGNAL(finished(bool)),
+            this, SLOT(onFileDownloadFinished(bool)), Qt::UniqueConnection);
+    setupTaskCleanup(task);
+
+    return task;
+}
+
+FileDownloadTask* DataManager::createSaveAsTask(const QString& repo_id,
+                                                const QString& path,
+                                                const QString& local_path)
+{
+    FileDownloadTask* task = TransferManager::instance()->addDownloadTask(
+        account_, repo_id, path, local_path, true);
+    setupTaskCleanup(task);
+
+    return task;
+}
+
+void DataManager::onFileDownloadFinished(bool success)
+{
+    qDebug("[onFileDownloadFinished function] invoked,is success %s",
+           success ? "true" : "false");
+    FileDownloadTask *task = qobject_cast<FileDownloadTask *>(sender());
+    if (task == NULL)
+        return;
+    if (success) {
+        filecache_->saveCachedFileId(task->repoId(),
+                                     task->path(),
+                                     account_.getSignature(),
+                                     task->fileId(),
+                                     task->localFilePath());
+        // TODO we don't want to watch readonly files
+        AutoUpdateManager::instance()->watchCachedFile(account_, task->repoId(), task->path());
+    }
+}
+
+FileUploadTask* DataManager::createUploadTask(const QString& repo_id,
+                                              const QString& parent_dir,
+                                              const QString& local_path,
+                                              const QString& name,
+                                              const bool overwrite)
+{
+    FileUploadTask *task;
+    if (QFileInfo(local_path).isFile())
+        task = new FileUploadTask(account_, repo_id, parent_dir,
+                                  local_path, name, !overwrite);
+    else
+        task = new FileUploadDirectoryTask(account_, repo_id, parent_dir,
+                                           local_path, name);
+    connect(task, SIGNAL(finished(bool)),
+            this, SLOT(onFileUploadFinished(bool)));
+    setupTaskCleanup(task);
+
+    return task;
+}
+
+void DataManager::setupTaskCleanup(FileNetworkTask *task)
+{
+    connect(this, SIGNAL(aboutToDestroy()),
+            task, SLOT(cancel()));
+}
+
+FileUploadTask* DataManager::createUploadMultipleTask(const QString& repo_id,
+                                                      const QString& parent_dir,
+                                                      const QString& local_path,
+                                                      const QStringList& names,
+                                                      const bool overwrite)
+{
+    FileUploadTask *task = new FileUploadMultipleTask(account_, repo_id, parent_dir,
+                                                      local_path, names, !overwrite);
+
+    connect(task, SIGNAL(finished(bool)),
+            this, SLOT(onFileUploadFinished(bool)));
+    setupTaskCleanup(task);
+
+    return task;
+}
+
+void DataManager::onFileUploadFinished(bool success)
+{
+    FileUploadTask *task = qobject_cast<FileUploadTask *>(sender());
+    if (task == NULL)
+        return;
+    if (success) {
+        //expire the parent path
+        dirents_cache_->expireCachedDirents(task->repoId(),
+                                            task->path());
+    }
+}
+
+QString DataManager::getLocalCacheFilePath(const QString& repo_id,
+                                           const QString& path)
+{
+    QString seafdir = seafApplet->configurator()->seafileDir();
+    return ::pathJoin(seafdir, kFileCacheTopDirName, repo_id, path);
+}
+
+QHash<QString, std::pair<qint64, QString> > DataManager::passwords_cache_;
+
+bool DataManager::isRepoPasswordSet(const QString& repo_id) const
+{
+    if (!passwords_cache_.contains(repo_id)) {
+        return false;
+    }
+    qint64 expiration_time = passwords_cache_[repo_id].first;
+    qint64 now = QDateTime::currentMSecsSinceEpoch();
+    return now < expiration_time;
+}
+
+void DataManager::setRepoPasswordSet(const QString& repo_id, const QString& password)
+{
+    passwords_cache_[repo_id] =
+        std::pair<qint64, QString>(QDateTime::currentMSecsSinceEpoch() + kPasswordCacheExpirationMSecs, password);
+}
+
+QString DataManager::getRepoCacheFolder(const QString& repo_id) const
+{
+    QString seafdir = seafApplet->configurator()->seafileDir();
+    return ::pathJoin(seafdir, kFileCacheTopDirName, repo_id);
+}
+
+void DataManager::createSubrepo(const QString &name, const QString& repo_id, const QString &path)
+{
+    old_repo_id_ = repo_id;
+    const QString password = repoPassword(repo_id);
+    const QString fixed_path = path.left(path.endsWith('/') && path.size() != 1 ? path.size() -1 : path.size());
+    create_subrepo_req_.reset(new CreateSubrepoRequest(account_, name, repo_id, fixed_path, password));
+    // we might have cleaned this value when do a new request while old request is still there
+    get_repo_req_.reset(NULL);
+    create_subrepo_parent_repo_id_ = repo_id;
+    create_subrepo_parent_path_ = fixed_path;
+
+    connect(create_subrepo_req_.data(), SIGNAL(success(const QString&)),
+            this, SLOT(onCreateSubrepoSuccess(const QString&)));
+    connect(create_subrepo_req_.data(), SIGNAL(failed(const ApiError&)),
+            this, SIGNAL(createSubrepoFailed(const ApiError&)));
+
+    create_subrepo_req_->send();
+}
+
+void DataManager::onCreateSubrepoSuccess(const QString& new_repoid)
+{
+    // if we have it, we are lucky
+    ServerRepo repo = RepoService::instance()->getRepo(new_repoid);
+    if (repo.isValid()) {
+        ServerRepo fixed_repo = repo;
+        fixed_repo.parent_path = create_subrepo_parent_path_;
+        fixed_repo.parent_repo_id = create_subrepo_parent_repo_id_;
+        emit createSubrepoSuccess(fixed_repo, old_repo_id_);
+        return;
+    }
+
+    // if not found, we need call get repo (list repo is not reliable here)
+    get_repo_req_.reset(new GetRepoRequest(account_, new_repoid));
+
+    // connect
+    connect(get_repo_req_.data(), SIGNAL(success(const ServerRepo&)),
+            this, SLOT(onCreateSubrepoRefreshSuccess(const ServerRepo&)));
+    connect(get_repo_req_.data(), SIGNAL(failed(const ApiError&)),
+            this, SIGNAL(createSubrepoFailed(const ApiError&)));
+
+    get_repo_req_->send();
+}
+
+void DataManager::onCreateSubrepoRefreshSuccess(const ServerRepo& repo)
+{
+    // okay, all green
+    if (repo.isValid()) {
+        ServerRepo fixed_repo = repo;
+        fixed_repo.parent_path = create_subrepo_parent_path_;
+        fixed_repo.parent_repo_id = create_subrepo_parent_repo_id_;
+        emit createSubrepoSuccess(fixed_repo, old_repo_id_);
+        return;
+    }
+
+    // it is not expected
+    emit createSubrepoFailed(ApiError::fromHttpError(500));
+}
+
+void DataManager::onAccountChanged()
+{
+    account_ = seafApplet->accountManager()->currentAccount();
+}
diff --git a/src/filebrowser/data-mgr.h b/src/filebrowser/data-mgr.h
new file mode 100644 (file)
index 0000000..01c3a67
--- /dev/null
@@ -0,0 +1,201 @@
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_DATA_MANAGER_H
+#define SEAFILE_CLIENT_FILE_BROWSER_DATA_MANAGER_H
+
+#include <QObject>
+#include <QHash>
+#include <QScopedPointer>
+#include <utility>
+
+#include "api/api-error.h"
+#include "account.h"
+#include "seaf-dirent.h"
+#include "utils/singleton.h"
+
+
+template<typename Key> class QList;
+
+class SeafileApiRequest;
+class GetDirentsRequest;
+class GetRepoRequest;
+class CreateSubrepoRequest;
+class DirentsCache;
+class FileCache;
+class FileCache;
+class FileNetworkTask;
+class FileUploadTask;
+class FileDownloadTask;
+
+/**
+ * DataManager is responsible for getting dirents/files from seahub, as well
+ * as the caching policy.
+ *
+ */
+class DataManager : public QObject {
+    SINGLETON_DEFINE(DataManager)
+    Q_OBJECT
+
+public:
+    DataManager();
+    ~DataManager();
+
+    void start();
+
+    const Account& account() const { return account_; }
+
+    bool getDirents(const QString& repo_id,
+                    const QString& path,
+                    QList<SeafDirent> *dirents,
+                    bool *current_readonly);
+
+    void getDirentsFromServer(const QString& repo_id,
+                              const QString& path);
+
+    void createDirectory(const QString &repo_id,
+                         const QString &path);
+
+    void renameDirent(const QString &repo_id,
+                      const QString &path,
+                      const QString &new_path,
+                      bool is_file);
+
+    void lockFile(const QString &repo_id,
+                  const QString &path,
+                  bool lock);
+
+    void removeDirent(const QString &repo_id,
+                      const QString &path,
+                      bool is_file);
+
+    void removeDirents(const QString &repo_id,
+                       const QString &parent_path,
+                       const QStringList &filenames);
+
+    void shareDirent(const QString &repo_id,
+                     const QString &path,
+                     bool is_file);
+
+    void copyDirents(const QString &repo_id,
+                     const QString &dir_path,
+                     const QStringList &file_names,
+                     const QString &dst_repo_id,
+                     const QString &dst_dir_path);
+
+    void moveDirents(const QString &repo_id,
+                     const QString &dir_path,
+                     const QStringList &file_names,
+                     const QString &dst_repo_id,
+                     const QString &dst_dir_path);
+
+    QString getLocalCachedFile(const QString& repo_id,
+                               const QString& path,
+                               const QString& file_id);
+
+    FileDownloadTask* createDownloadTask(const QString& repo_id,
+                                         const QString& path);
+
+    FileDownloadTask* createSaveAsTask(const QString& repo_id,
+                                       const QString& path,
+                                       const QString& local_path);
+
+    FileUploadTask* createUploadTask(const QString& repo_id,
+                                     const QString& parent_dir,
+                                     const QString& local_path,
+                                     const QString& name,
+                                     const bool overwrite);
+
+    FileUploadTask* createUploadMultipleTask(const QString& repo_id,
+                                             const QString& parent_dir,
+                                             const QString& local_path,
+                                             const QStringList& names,
+                                             const bool overwrite);
+
+    bool isRepoPasswordSet(const QString& repo_id) const;
+    QString repoPassword(const QString& repo_id) const {
+        if (!isRepoPasswordSet(repo_id))
+            return QString();
+        return passwords_cache_[repo_id].second;
+    }
+    void setRepoPasswordSet(const QString& repo_id, const QString& password);
+
+    QString getRepoCacheFolder(const QString& repo_id) const;
+
+    static QString getLocalCacheFilePath(const QString& repo_id,
+                                         const QString& path);
+
+    void createSubrepo(const QString &name, const QString& repo_id, const QString &path);
+
+signals:
+    void aboutToDestroy();
+
+    void getDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents, const QString& repo_id);
+    void getDirentsFailed(const ApiError& error, const QString& repo_id);
+
+    void createDirectorySuccess(const QString& path, const QString& repo_id);
+    void createDirectoryFailed(const ApiError& error);
+
+    void lockFileSuccess(const QString& path, bool lock, const QString& repo_id);
+    void lockFileFailed(const ApiError& error);
+
+    void renameDirentSuccess(const QString& path, const QString& new_name, const QString& repo_id);
+    void renameDirentFailed(const ApiError& error);
+
+    void removeDirentSuccess(const QString& path, const QString& repo_id);
+    void removeDirentFailed(const ApiError& error);
+
+    void removeDirentsSuccess(const QString& parent_path, const QStringList& filenames, const QString& repo_id);
+    void removeDirentsFailed(const ApiError& error);
+
+    void shareDirentSuccess(const QString& link, const QString& repo_id);
+    void shareDirentFailed(const ApiError& error);
+
+    void copyDirentsSuccess(const QString& dst_repo_id);
+    void copyDirentsFailed(const ApiError& error);
+
+    void moveDirentsSuccess(const QString& dst_repo_id);
+    void moveDirentsFailed(const ApiError& error);
+
+    void createSubrepoSuccess(const ServerRepo &repo, const QString& repo_id);
+    void createSubrepoFailed(const ApiError& error);
+
+private slots:
+    void onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents, const QString& repo_id);
+    void onFileUploadFinished(bool success);
+    void onFileDownloadFinished(bool success);
+
+    void onCreateDirectorySuccess(const QString& repo_id);
+    void onLockFileSuccess(const QString& repo_id);
+    void onRenameDirentSuccess(const QString& repo_id);
+    void onRemoveDirentSuccess(const QString& repo_id);
+    void onRemoveDirentsSuccess(const QString& repo_id);
+    void onCopyDirentsSuccess(const QString& dst_repo_id);
+    void onMoveDirentsSuccess(const QString& dst_repo_id);
+
+    void onCreateSubrepoSuccess(const QString& new_repoid);
+    void onCreateSubrepoRefreshSuccess(const ServerRepo& new_repo);
+
+    void onAccountChanged();
+
+private:
+    void removeDirentsCache(const QString& repo_id,
+                            const QString& path,
+                            bool is_file);
+    void setupTaskCleanup(FileNetworkTask *task);
+    Account account_;
+
+    QScopedPointer<CreateSubrepoRequest, QScopedPointerDeleteLater> create_subrepo_req_;
+    QString create_subrepo_parent_repo_id_;
+    QString create_subrepo_parent_path_;
+    QScopedPointer<GetRepoRequest, QScopedPointerDeleteLater> get_repo_req_;
+
+    QList<SeafileApiRequest*> reqs_;
+
+    FileCache *filecache_;
+
+    DirentsCache *dirents_cache_;
+    QString old_repo_id_;
+
+    static QHash<QString, std::pair<qint64, QString> > passwords_cache_;
+};
+
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_DATA_MANAGER_H
diff --git a/src/filebrowser/file-browser-dialog.cpp b/src/filebrowser/file-browser-dialog.cpp
new file mode 100644 (file)
index 0000000..ff03431
--- /dev/null
@@ -0,0 +1,1742 @@
+#include <QtGlobal>
+#include <QtWidgets>
+#include <QDesktopServices>
+#include <QHBoxLayout>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "utils/utils.h"
+#include "utils/paint-utils.h"
+#include "utils/file-utils.h"
+#include "api/api-error.h"
+#include "file-table.h"
+#include "seaf-dirent.h"
+#include "ui/loading-view.h"
+#include "data-mgr.h"
+#include "data-mgr.h"
+#include "progress-dialog.h"
+#include "tasks.h"
+#include "ui/set-repo-password-dialog.h"
+#include "sharedlink-dialog.h"
+#include "seafilelink-dialog.h"
+#include "auto-update-mgr.h"
+#include "transfer-mgr.h"
+#include "repo-service.h"
+#include "rpc/local-repo.h"
+#include "rpc/rpc-client.h"
+#include "ui/private-share-dialog.h"
+#include "ui/logout-view.h"
+
+#include "file-browser-manager.h"
+#include "file-browser-dialog.h"
+
+#include "ui/download-repo-dialog.h"
+
+#include "QtAwesome.h"
+
+namespace {
+
+enum {
+    INDEX_LOADING_VIEW = 0,
+    INDEX_TABLE_VIEW,
+    INDEX_LOADING_FAILED_VIEW,
+    INDEX_EMPTY_VIEW,
+    INDEX_RELOGIN_VIEW,
+    INDEX_SEARCH_VIEW
+};
+
+const char *kLoadingFailedLabelName = "LoadingFailedText";
+const int kToolBarIconSize = 24;
+const int kStatusBarIconSize = 20;
+const int kAllPage = 1;
+const int kPerPageCount = 10000;
+const int kSearchBarWidth = 250;
+//const int kStatusCodePasswordNeeded = 400;
+
+void openFile(const QString& path)
+{
+    ::openInNativeExtension(path) || ::showInGraphicalShell(path);
+#ifdef Q_OS_MAC
+    MacImageFilesWorkAround::instance()->fileOpened(path);
+#endif
+}
+
+bool inline findConflict(const QString &name, const QList<SeafDirent> &dirents) {
+    bool found_conflict = false;
+    // find if there exist a file with the same name
+    Q_FOREACH(const SeafDirent &dirent, dirents)
+    {
+        if (dirent.name == name) {
+            found_conflict = true;
+            break;
+        }
+    }
+    return found_conflict;
+}
+
+QString appendTrailingSlash(const QString& input) {
+    return input.endsWith('/') ? input : input + '/';
+}
+
+} // namespace
+
+QStringList FileBrowserDialog::file_names_to_be_pasted_;
+QString FileBrowserDialog::dir_path_to_be_pasted_from_;
+QString FileBrowserDialog::repo_id_to_be_pasted_from_;
+Account FileBrowserDialog::account_to_be_pasted_from_;
+bool FileBrowserDialog::is_copyed_when_pasted_;
+
+FileBrowserDialog::FileBrowserDialog(const Account &account, const ServerRepo& repo, const QString &path, QWidget *parent)
+    : QDialog(parent),
+      account_(account),
+      repo_(repo),
+      current_path_(path),
+      current_readonly_(repo_.readonly),
+      search_request_(NULL),
+      search_text_last_modified_(0),
+      has_password_dialog_(false)
+{
+    current_lpath_ = current_path_.split('/');
+
+    data_mgr_ = seafApplet->dataManager();
+
+    // In German translation there is a "seafile" string, so need to use tr("..").arg(..) here
+    QString title = tr("Cloud File Browser");
+    if (title.contains("%")) {
+        title = title.arg(getBrand());
+    }
+    setWindowTitle(title);
+    setWindowIcon(QIcon(":/images/seafile.png"));
+
+    Qt::WindowFlags flags =
+        (windowFlags() & ~Qt::WindowContextHelpButtonHint & ~Qt::Dialog) |
+        Qt::Window | Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint |
+        Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint |
+        Qt::WindowMaximizeButtonHint;
+
+    setWindowFlags(flags);
+
+    // setAttribute(Qt::WA_TranslucentBackground, true);
+
+    createToolBar();
+    createStatusBar();
+    createLoadingFailedView();
+    createEmptyView();
+    createFileTable();
+
+    relogin_view_ = new LogoutView;
+
+    QWidget* widget = new QWidget;
+    widget->setObjectName("mainWidget");
+    QVBoxLayout* layout = new QVBoxLayout;
+    layout->setContentsMargins(0, 0, 0, 0);
+    layout->setSpacing(0);
+    setLayout(layout);
+    layout->addWidget(widget);
+
+    QVBoxLayout *vlayout = new QVBoxLayout;
+    vlayout->setContentsMargins(1, 0, 1, 0);
+    vlayout->setSpacing(0);
+    widget->setLayout(vlayout);
+
+    QHBoxLayout *hlayout = new QHBoxLayout;
+    hlayout->setContentsMargins(1, 0, 1, 0);
+    hlayout->setSpacing(0);
+    hlayout->addWidget(toolbar_);
+    hlayout->addWidget(search_toolbar_);
+
+    search_view_ = new FileBrowserSearchView(this);
+    search_view_->setObjectName("searchResult");
+#ifdef Q_OS_MAC
+    search_view_->setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+    search_model_ = new FileBrowserSearchModel(this);
+    search_view_->setModel(search_model_);
+    search_view_->setColumnWidth(0,265);
+    search_view_->setColumnWidth(1,165);
+    search_view_->setColumnWidth(2,95);
+    search_delegate_ = new FileBrowserSearchItemDelegate(this);
+    delete search_view_->itemDelegate();
+    search_view_->setItemDelegate(search_delegate_);
+
+    stack_ = new QStackedWidget;
+    stack_->insertWidget(INDEX_LOADING_VIEW, loading_view_);
+    stack_->insertWidget(INDEX_TABLE_VIEW, table_view_);
+    stack_->insertWidget(INDEX_LOADING_FAILED_VIEW, loading_failed_view_);
+    stack_->insertWidget(INDEX_EMPTY_VIEW, empty_view_);
+    stack_->insertWidget(INDEX_RELOGIN_VIEW, relogin_view_);
+    stack_->insertWidget(INDEX_SEARCH_VIEW, search_view_);
+    stack_->setContentsMargins(0, 0, 0, 0);
+    stack_->installEventFilter(this);
+    stack_->setAcceptDrops(true);
+
+    vlayout->addLayout(hlayout);
+    vlayout->addWidget(stack_);
+    vlayout->addWidget(status_bar_);
+
+    search_timer_ = new QTimer(this);
+    connect(search_timer_, SIGNAL(timeout()), this, SLOT(doRealSearch()));
+    search_timer_->start(300);
+
+    // this <--> table_view_
+    connect(table_view_, SIGNAL(direntClicked(const SeafDirent&)),
+            this, SLOT(onDirentClicked(const SeafDirent&)));
+    connect(table_view_, SIGNAL(direntSaveAs(const QList<const SeafDirent*>&)),
+            this, SLOT(onDirentSaveAs(const QList<const SeafDirent*>&)));
+    connect(table_view_, SIGNAL(direntLock(const SeafDirent&)),
+            this, SLOT(onGetDirentLock(const SeafDirent&)));
+    connect(table_view_, SIGNAL(direntRename(const SeafDirent&)),
+            this, SLOT(onGetDirentRename(const SeafDirent&)));
+    connect(table_view_, SIGNAL(direntRemove(const SeafDirent&)),
+            this, SLOT(onGetDirentRemove(const SeafDirent&)));
+    connect(table_view_, SIGNAL(direntRemove(const QList<const SeafDirent*> &)),
+            this, SLOT(onGetDirentRemove(const QList<const SeafDirent*> &)));
+    connect(table_view_, SIGNAL(direntShare(const SeafDirent&)),
+            this, SLOT(onGetDirentShare(const SeafDirent&)));
+    connect(table_view_, SIGNAL(direntShareToUserOrGroup(const SeafDirent&, bool)),
+            this, SLOT(onGetDirentShareToUserOrGroup(const SeafDirent&, bool)));
+    connect(table_view_, SIGNAL(direntShareSeafile(const SeafDirent&)),
+            this, SLOT(onGetDirentShareSeafile(const SeafDirent&)));
+    connect(table_view_, SIGNAL(direntUpdate(const SeafDirent&)),
+            this, SLOT(onGetDirentUpdate(const SeafDirent&)));
+    connect(table_view_, SIGNAL(direntPaste()),
+            this, SLOT(onGetDirentsPaste()));
+    connect(table_view_, SIGNAL(cancelDownload(const SeafDirent&)),
+            this, SLOT(onCancelDownload(const SeafDirent&)));
+    connect(table_view_, SIGNAL(syncSubdirectory(const QString&)),
+            this, SLOT(onGetSyncSubdirectory(const QString &)));
+    connect(table_view_, SIGNAL(deleteLocalVersion(const SeafDirent&)),
+            this, SLOT(onDeleteLocalVersion(const SeafDirent&)));
+    connect(table_view_, SIGNAL(localVersionSaveAs(const SeafDirent&)),
+            this, SLOT(onLocalVersionSaveAs(const SeafDirent&)));
+
+    connect(search_view_, SIGNAL(clearSearchBar()),
+            search_bar_, SLOT(clear()));
+
+
+    //dirents <--> data_mgr_
+    data_mgr_notify_ = new DataManagerNotify(repo_.id);
+    connect(data_mgr_notify_, SIGNAL(getDirentsSuccess(bool, const QList<SeafDirent>&)),
+            this, SLOT(onGetDirentsSuccess(bool, const QList<SeafDirent>&)));
+    connect(data_mgr_notify_, SIGNAL(getDirentsFailed(const ApiError&)),
+            this, SLOT(onGetDirentsFailed(const ApiError&)));
+
+    //create <--> data_mgr_
+    connect(data_mgr_notify_, SIGNAL(createDirectorySuccess(const QString&)),
+            this, SLOT(onDirectoryCreateSuccess(const QString&)));
+    connect(data_mgr_, SIGNAL(createDirectoryFailed(const ApiError&)),
+            this, SLOT(onDirectoryCreateFailed(const ApiError&)));
+
+    //lock <--> data_mgr_
+    connect(data_mgr_notify_, SIGNAL(lockFileSuccess(const QString&, bool)),
+            this, SLOT(onFileLockSuccess(const QString&, bool)));
+    connect(data_mgr_, SIGNAL(lockFileFailed(const ApiError&)),
+            this, SLOT(onFileLockFailed(const ApiError&)));
+
+    //rename <--> data_mgr_
+    connect(data_mgr_notify_, SIGNAL(renameDirentSuccess(const QString&, const QString&)),
+            this, SLOT(onDirentRenameSuccess(const QString&, const QString&)));
+    connect(data_mgr_, SIGNAL(renameDirentFailed(const ApiError&)),
+            this, SLOT(onDirentRenameFailed(const ApiError&)));
+
+    //remove <--> data_mgr_
+    connect(data_mgr_notify_, SIGNAL(removeDirentSuccess(const QString&)),
+            this, SLOT(onDirentRemoveSuccess(const QString&)));
+    connect(data_mgr_, SIGNAL(removeDirentFailed(const ApiError&)),
+            this, SLOT(onDirentRemoveFailed(const ApiError&)));
+
+    connect(data_mgr_notify_, SIGNAL(removeDirentsSuccess(const QString&, const QStringList&)),
+            this, SLOT(onDirentsRemoveSuccess(const QString&, const QStringList&)));
+    connect(data_mgr_, SIGNAL(removeDirentsFailed(const ApiError&)),
+            this, SLOT(onDirentsRemoveFailed(const ApiError&)));
+
+    //share <--> data_mgr_
+    connect(data_mgr_notify_, SIGNAL(shareDirentSuccess(const QString&)),
+            this, SLOT(onDirentShareSuccess(const QString&)));
+    connect(data_mgr_, SIGNAL(shareDirentFailed(const ApiError&)),
+            this, SLOT(onDirentShareFailed(const ApiError&)));
+
+    //copy <--> data_mgr_
+    connect(data_mgr_notify_, SIGNAL(copyDirentsSuccess()),
+            this, SLOT(onDirentsCopySuccess()));
+    connect(data_mgr_, SIGNAL(copyDirentsFailed(const ApiError&)),
+            this, SLOT(onDirentsCopyFailed(const ApiError&)));
+
+    //move <--> data_mgr_
+    connect(data_mgr_notify_, SIGNAL(moveDirentsSuccess()),
+            this, SLOT(onDirentsMoveSuccess()));
+    connect(data_mgr_, SIGNAL(moveDirentsFailed(const ApiError&)),
+            this, SLOT(onDirentsMoveFailed(const ApiError&)));
+
+    //subrepo <-->data_mgr_
+    connect(data_mgr_notify_, SIGNAL(createSubrepoSuccess(const ServerRepo &)),
+            this, SLOT(onCreateSubrepoSuccess(const ServerRepo &)));
+    connect(data_mgr_, SIGNAL(createSubrepoFailed(const ApiError&)),
+            this, SLOT(onCreateSubrepoFailed(const ApiError&)));
+
+    connect(AutoUpdateManager::instance(), SIGNAL(fileUpdated(const QString&, const QString&)),
+            this, SLOT(onFileAutoUpdated(const QString&, const QString&)));
+
+    AccountManager* account_mgr = seafApplet->accountManager();
+    connect(account_mgr, SIGNAL(accountInfoUpdated(const Account&)), this,
+            SLOT(onAccountInfoUpdated()));
+
+    QTimer::singleShot(0, this, SLOT(init()));
+
+}
+
+FileBrowserDialog::~FileBrowserDialog()
+{
+    if (search_request_ != NULL)
+        search_request_->deleteLater();
+    delete data_mgr_notify_;
+}
+
+void FileBrowserDialog::init()
+{
+    enterPath(current_path_);
+}
+
+void FileBrowserDialog::createToolBar()
+{
+    toolbar_ = new QToolBar;
+    toolbar_->setObjectName("topBar");
+    toolbar_->setIconSize(QSize(kToolBarIconSize, kToolBarIconSize));
+
+    backward_button_ = new QToolButton(this);
+    backward_button_->setText(tr("Back"));
+    backward_button_->setObjectName("backwardButton");
+    backward_button_->setIcon(QIcon(":/images/filebrowser/backward.png"));
+    backward_button_->setEnabled(false);
+    backward_button_->setShortcut(QKeySequence::Back);
+    toolbar_->addWidget(backward_button_);
+    connect(backward_button_, SIGNAL(clicked()), this, SLOT(goBackward()));
+
+    forward_button_ = new QToolButton(this);
+    forward_button_->setText(tr("Forward"));
+    forward_button_->setObjectName("forwardButton");
+    forward_button_->setIcon(QIcon(":/images/filebrowser/forward.png"));
+    forward_button_->setEnabled(false);
+    forward_button_->setShortcut(QKeySequence::Forward);
+    toolbar_->addWidget(forward_button_);
+    connect(forward_button_, SIGNAL(clicked()), this, SLOT(goForward()));
+
+    // XX: not sure why, but we have to set the styles here, otherwise it won't
+    // work (if we write this in qt.css)
+    backward_button_->setStyleSheet("QToolButton { margin-right: -2px; }");
+    forward_button_->setStyleSheet("QToolButton { margin-left: -2px; margin-right: 10px;}");
+    toolbar_->setStyleSheet("QToolbar { spacing: 0px; }");
+
+    gohome_action_ = new QAction(tr("Home"), this);
+    gohome_action_->setIcon(QIcon(":images/filebrowser/home.png"));
+    connect(gohome_action_, SIGNAL(triggered()), this, SLOT(goHome()));
+    toolbar_->addAction(gohome_action_);
+    toolbar_->widgetForAction(gohome_action_)->setObjectName("goHomeButton");
+
+    path_navigator_ = new QButtonGroup(this);
+    connect(path_navigator_, SIGNAL(buttonClicked(int)),
+            this, SLOT(onNavigatorClick(int)));
+
+    search_toolbar_ = new QToolBar;
+    search_toolbar_->setObjectName("topBar");
+    search_toolbar_->setIconSize(QSize(kToolBarIconSize, kToolBarIconSize));
+    search_toolbar_->setFixedWidth(kSearchBarWidth);
+    search_toolbar_->setStyleSheet("QToolbar { spacing: 0px; }");
+
+    search_bar_ = new SearchBar;
+    search_bar_->setPlaceholderText(tr("Search files"));
+    search_toolbar_->addWidget(search_bar_);
+    connect(search_bar_, SIGNAL(textChanged(const QString&)),
+            this, SLOT(doSearch(const QString&)));
+    if (!account_.isPro()) {
+        search_toolbar_->setVisible(false);
+    }
+}
+
+void FileBrowserDialog::createStatusBar()
+{
+    status_bar_ = new QWidget;
+    status_bar_->setObjectName("statusBar");
+
+    status_layout_ = new QHBoxLayout(status_bar_);
+    status_layout_->setContentsMargins(0, 0, 0, 0);
+
+    // Submenu
+    upload_menu_ = new QMenu;
+    connect(upload_menu_, SIGNAL(aboutToShow()), this, SLOT(fixUploadButtonHighlightStyle()));
+    connect(upload_menu_, SIGNAL(aboutToHide()), this, SLOT(fixUploadButtonNonHighlightStyle()));
+
+    // Submenu's Action 1: Upload File
+    upload_file_action_ = new QAction(tr("Upload files"), upload_menu_);
+    connect(upload_file_action_, SIGNAL(triggered()), this, SLOT(chooseFileToUpload()));
+    upload_menu_->addAction(upload_file_action_);
+
+    upload_directory_action_ = new QAction(tr("Upload a directory"), upload_menu_);
+    connect(upload_directory_action_, SIGNAL(triggered()), this, SLOT(chooseDirectoryToUpload()));
+    upload_menu_->addAction(upload_directory_action_);
+
+    // Submenu's Action 3: Make a new directory
+    mkdir_action_ = new QAction(tr("Create a folder"), upload_menu_);
+    connect(mkdir_action_, SIGNAL(triggered()), this, SLOT(onMkdirButtonClicked()));
+    upload_menu_->addAction(mkdir_action_);
+
+    // Action to trigger Submenu
+    upload_button_ = new QToolButton;
+    upload_button_->setObjectName("uploadButton");
+    upload_button_->setToolTip(tr("Upload files"));
+    upload_button_->setIcon(QIcon(":/images/filebrowser/add.png"));
+    upload_button_->setIconSize(QSize(kStatusBarIconSize, kStatusBarIconSize));
+    upload_button_->installEventFilter(this);
+    connect(upload_button_, SIGNAL(clicked()), this, SLOT(uploadFileOrMkdir()));
+    status_layout_->addWidget(upload_button_);
+
+    if (current_readonly_) {
+        upload_button_->setEnabled(false);
+        upload_button_->setToolTip(tr("You don't have permission to upload files to this library"));
+    }
+
+    details_label_ = new QLabel;
+    details_label_->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
+    details_label_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+    status_layout_->addWidget(details_label_);
+
+    refresh_button_ = new QToolButton;
+    refresh_button_->setObjectName("refreshButton");
+    refresh_button_->setToolTip(tr("Refresh"));
+    refresh_button_->setIcon(QIcon(":/images/filebrowser/refresh-gray.png"));
+    refresh_button_->setIconSize(QSize(kStatusBarIconSize, kStatusBarIconSize));
+    refresh_button_->installEventFilter(this);
+    connect(refresh_button_, SIGNAL(clicked()), this, SLOT(onRefresh()));
+    status_layout_->addWidget(refresh_button_);
+}
+
+void FileBrowserDialog::createFileTable()
+{
+    loading_view_ = new LoadingView;
+    table_view_ = new FileTableView(this);
+    table_model_ = new FileTableModel(this);
+    table_view_->setModel(table_model_);
+    table_view_->setColumnWidth(0,260);
+    table_view_->setColumnWidth(1,165);
+    table_view_->setColumnWidth(2,95);
+}
+
+bool FileBrowserDialog::handleDragDropEvent(QObject *obj, QEvent *event)
+{
+    if (event->type() == QEvent::DragEnter) {
+        QDragEnterEvent* ev = (QDragEnterEvent*)event;
+        // only handle external source currently
+        if(ev->source() != NULL)
+            return false;
+        // Otherwise it might be a MoveAction which is unacceptable
+        ev->setDropAction(Qt::CopyAction);
+        // trivial check
+        if(ev->mimeData()->hasFormat("text/uri-list"))
+            ev->accept();
+        return true;
+    }
+    else if (event->type() == QEvent::Drop) {
+        QDropEvent* ev = (QDropEvent*)event;
+        // only handle external source currently
+        if(ev->source() != NULL)
+            return false;
+
+        QList<QUrl> urls = ev->mimeData()->urls();
+
+        if(urls.isEmpty())
+            return false;
+
+        QStringList paths;
+        Q_FOREACH(const QUrl& url, urls)
+        {
+            QString path = url.toLocalFile();
+#if defined(Q_OS_MAC) && (QT_VERSION <= QT_VERSION_CHECK(5, 4, 0))
+            path = utils::mac::fix_file_id_url(path);
+#endif
+            if(path.isEmpty())
+                continue;
+            paths.push_back(path);
+        }
+
+        ev->accept();
+
+        if (current_readonly_) {
+            seafApplet->warningBox(tr("You do not have permission to upload to this folder"), this);
+        } else {
+            uploadOrUpdateMutipleFile(paths);
+        }
+        return true;
+    }
+    else {
+        return QObject::eventFilter(obj, event);
+    }
+}
+
+bool FileBrowserDialog::eventFilter(QObject *obj, QEvent *event)
+{
+    if (obj == upload_button_) {
+        // Sometimes the upload menu is dismissed, the upload button style won't
+        // change, and we need to handle it manually here as well as in the
+        // aboutToHide signal of the upload_meu. This might be a qt bug.
+        if (event->type() == QEvent::Enter) {
+            fixUploadButtonHighlightStyle();
+            return true;
+        } else if (event->type() == QEvent::Leave) {
+            fixUploadButtonNonHighlightStyle();
+            return true;
+        }
+    } else if (obj == refresh_button_) {
+        if (event->type() == QEvent::Enter) {
+            refresh_button_->setStyleSheet("FileBrowserDialog QToolButton#refreshButton {"
+                                          "background: #DFDFDF; padding: 3px;"
+                                          "margin-right: 12px; border-radius: 2px;}");
+            return true;
+        } else if (event->type() == QEvent::Leave) {
+            refresh_button_->setStyleSheet("FileBrowserDialog QToolButton#refreshButton {"
+                                          "background: #F5F5F7; padding: 0px;"
+                                          "margin-right: 15px;}");
+            return true;
+        }
+    } else if (obj == stack_) {
+        if (stack_->currentIndex() == INDEX_EMPTY_VIEW ||
+            stack_->currentIndex() == INDEX_TABLE_VIEW) {
+            return handleDragDropEvent(obj, event);
+        }
+    }
+
+    return QObject::eventFilter(obj, event);
+}
+
+void FileBrowserDialog::onRefresh()
+{
+    if (!seafApplet->accountManager()->currentAccount().isValid()) {
+            stack_->setCurrentIndex(INDEX_RELOGIN_VIEW);
+            return;
+    }
+    if (!search_bar_->text().isEmpty()) {
+        search_text_last_modified_ = 1;
+        doRealSearch();
+    } else {
+        forceRefresh();
+    }
+}
+
+void FileBrowserDialog::forceRefresh()
+{
+    fetchDirents(true);
+}
+
+void FileBrowserDialog::fetchDirents()
+{
+    fetchDirents(false);
+}
+
+void FileBrowserDialog::updateFileCount()
+{
+    int row_count = 0;
+    if (stack_->currentIndex() == INDEX_TABLE_VIEW)
+        row_count = table_model_->rowCount();
+    if (stack_->currentIndex() == INDEX_SEARCH_VIEW)
+        row_count = search_model_->rowCount();
+
+    details_label_->setText(tr("%1 items").arg(row_count));
+}
+
+void FileBrowserDialog::fetchDirents(bool force_refresh)
+{
+    if (!has_password_dialog_ && repo_.encrypted && !data_mgr_->isRepoPasswordSet(repo_.id)) {
+        has_password_dialog_ = true;
+        SetRepoPasswordDialog password_dialog(repo_, this);
+        if (password_dialog.exec() != QDialog::Accepted) {
+            reject();
+            return;
+        } else {
+            has_password_dialog_ = false;
+            data_mgr_->setRepoPasswordSet(repo_.id, password_dialog.password());
+        }
+    }
+
+    if (!force_refresh) {
+        QList<SeafDirent> dirents;
+        if (data_mgr_->getDirents(repo_.id, current_path_, &dirents, &current_readonly_)) {
+            updateTable(dirents);
+            return;
+        }
+    }
+
+    showLoading();
+    data_mgr_->getDirentsFromServer(repo_.id, current_path_);
+}
+
+void FileBrowserDialog::onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents)
+{
+    current_readonly_ = current_readonly;
+    updateTable(dirents);
+}
+
+void FileBrowserDialog::onGetDirentsFailed(const ApiError& error)
+{
+    if (error.httpErrorCode() == 401) {
+        stack_->setCurrentIndex(INDEX_RELOGIN_VIEW);
+    } else {
+        stack_->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+    }
+}
+
+void FileBrowserDialog::onMkdirButtonClicked()
+{
+    QString name = seafApplet->getText(this, tr("Create a folder"),
+        tr("Folder name"));
+    name = name.trimmed();
+
+    if (name.isEmpty())
+        return;
+
+    // invalid name
+    if (name.contains("/")) {
+        seafApplet->warningBox(tr("Invalid folder name!"), this);
+        return;
+    }
+
+    if (findConflict(name, table_model_->dirents())) {
+        seafApplet->warningBox(
+            tr("The name \"%1\" is already taken.").arg(name), this);
+        return;
+    }
+
+    createDirectory(name);
+}
+
+void FileBrowserDialog::createLoadingFailedView()
+{
+    loading_failed_view_ = new QLabel;
+    loading_failed_view_->setObjectName(kLoadingFailedLabelName);
+    QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("retry"));
+    QString label_text = tr("Failed to get files information<br/>"
+                            "Please %1").arg(link);
+    loading_failed_view_->setText(label_text);
+    loading_failed_view_->setAlignment(Qt::AlignCenter);
+
+    connect(loading_failed_view_, SIGNAL(linkActivated(const QString&)),
+            this, SLOT(onRefresh()));
+}
+
+void FileBrowserDialog::createEmptyView()
+{
+    empty_view_ = new QLabel(this);
+    empty_view_->setText(tr("This folder is empty."));
+    empty_view_->setAlignment(Qt::AlignCenter);
+    empty_view_->setStyleSheet("background-color: white;");
+}
+
+void FileBrowserDialog::onDirentClicked(const SeafDirent& dirent)
+{
+    if (dirent.isDir()) {
+        onDirClicked(dirent);
+    } else {
+        onFileClicked(dirent);
+    }
+}
+
+void FileBrowserDialog::onDirentSaveAs(const QList<const SeafDirent*>& dirents)
+{
+    static QDir download_dir(defaultDownloadDir());
+    if (dirents.isEmpty())
+        return;
+    if (!download_dir.exists())
+        download_dir = QDir::home();
+
+    // handle when we have only one file
+    if (dirents.size() == 1) {
+        const SeafDirent &dirent = *dirents.front();
+        QString local_path = QFileDialog::getSaveFileName(this, tr("Enter name of file to save to..."), download_dir.filePath(dirent.name));
+        if (local_path.isEmpty())
+            return;
+        download_dir = QFileInfo(local_path).dir();
+        if (QFileInfo(local_path).exists()) {
+          // it is asked by the QFileDialog::getSaveFileName if overwrite the file
+          if (!QFile::remove(local_path)) {
+              seafApplet->warningBox(tr("Unable to remove file \"%1\""), this);
+              return;
+          }
+        }
+        FileDownloadTask *task = data_mgr_->createSaveAsTask(repo_.id, ::pathJoin(current_path_, dirent.name), local_path);
+        connect(task, SIGNAL(finished(bool)), this, SLOT(onDownloadFinished(bool)));
+        return;
+    }
+
+    QString local_dir = QFileDialog::getExistingDirectory(this, tr("Enter the path of the folder you want to save to..."), download_dir.path());
+    if (local_dir.isEmpty())
+        return;
+    download_dir = local_dir;
+    //
+    // scan for existing files and folders
+    // then begin downloading
+    //
+    Q_FOREACH(const SeafDirent* dirent, dirents) {
+        QString local_path = ::pathJoin(local_dir, dirent->name);
+        if  (QFileInfo(local_path).exists()) {
+              if (!seafApplet->yesOrNoBox(tr("Do you want to overwrite the existing file \"%1\"?").arg(dirent->name))) {
+                  return;
+              }
+              if (!QFile::remove(local_path)) {
+                  seafApplet->warningBox(tr("Unable to remove file \"%1\""), this);
+                  return;
+              }
+        }
+        // get them to be downloaded
+        FileDownloadTask *task = data_mgr_->createSaveAsTask(repo_.id, ::pathJoin(current_path_, dirent->name), local_path);
+        connect(task, SIGNAL(finished(bool)), this, SLOT(onDownloadFinished(bool)));
+    }
+}
+
+void FileBrowserDialog::showLoading()
+{
+    forward_button_->setEnabled(false);
+    backward_button_->setEnabled(false);
+    upload_button_->setEnabled(false);
+    gohome_action_->setEnabled(false);
+    stack_->setCurrentIndex(INDEX_LOADING_VIEW);
+}
+
+void FileBrowserDialog::onDirClicked(const SeafDirent& dir)
+{
+    const QString& path = ::pathJoin(current_path_, dir.name);
+    backward_history_.push(current_path_);
+    forward_history_.clear();
+    enterPath(path);
+}
+
+void FileBrowserDialog::enterPath(const QString& path)
+{
+    // printf ("enter path %s\n", toCStr(path));
+    current_path_ = path;
+    // use QUrl::toPercentEncoding if need
+    fetchDirents();
+
+    // QHash<QString, AutoUpdateManager::FileStatus> uploads =
+    //     AutoUpdateManager::instance()->getFileStatusForDirectory(
+    //         account_.getSignature(), repo_.id, path);
+    // if (uploads.empty()) {
+    //     printf("no uploads for dir %s\n", toCStr(path));
+    // }
+    // foreach(const QString& key, uploads.keys()) {
+    //     printf("auto upload status: file=\"%s\", uploading=%d\n", toCStr(key), uploads[key]);
+    // }
+
+    // current_path should be guaranteed safe to split!
+    current_lpath_ = current_path_.split('/');
+    // if the last element is empty (i.e. current_path_ ends with an extra "/"),
+    // remove it
+    if(current_lpath_.last().isEmpty())
+        current_lpath_.pop_back();
+
+    // remove all old buttons for navigator except the root
+    QList<QAbstractButton *> buttons = path_navigator_->buttons();
+    Q_FOREACH(QAbstractButton *button, buttons)
+    {
+        path_navigator_->removeButton(button);
+        delete button;
+    }
+    Q_FOREACH(QLabel *label, path_navigator_separators_)
+    {
+        delete label;
+    }
+    path_navigator_separators_.clear();
+
+    gohome_action_->setEnabled(path != "/");
+
+    // root is special
+    if (path == "/") {
+        QLabel *root = new QLabel(repo_.name);
+        toolbar_->addWidget(root);
+        path_navigator_separators_.push_back(root);
+    } else {
+        QPushButton *root = new QPushButton(repo_.name);
+        root->setObjectName("homeButton");
+        root->setFlat(true);
+        root->setCursor(Qt::PointingHandCursor);
+        toolbar_->addWidget(root);
+        path_navigator_->addButton(root, 0);
+
+        // add new buttons for navigator except the root
+        for(int i = 1; i < current_lpath_.size(); i++) {
+            QLabel *separator = new QLabel("/");
+            separator->setBaseSize(4, 7);
+            separator->setPixmap(QIcon(":/images/filebrowser/path-separator.png").pixmap(10));
+            path_navigator_separators_.push_back(separator);
+            toolbar_->addWidget(separator);
+            if (i != current_lpath_.size() - 1) {
+                QPushButton* button = new QPushButton(current_lpath_[i]);
+                button->setFlat(true);
+                button->setCursor(Qt::PointingHandCursor);
+                path_navigator_->addButton(button, i);
+                toolbar_->addWidget(button);
+            } else {
+                QLabel *separator = new QLabel(current_lpath_[i]);
+                toolbar_->addWidget(separator);
+                path_navigator_separators_.push_back(separator);
+            }
+        }
+    }
+}
+
+void FileBrowserDialog::onFileClicked(const SeafDirent& file)
+{
+    QString fpath = ::pathJoin(current_path_, file.name);
+
+    LocalRepo repo;
+    if (seafApplet->rpcClient()->getLocalRepo(repo_.id, &repo) == 0) {
+        QString synced_path = ::pathJoin(repo.worktree, fpath);
+        if (!QFileInfo(synced_path).exists()) {
+            seafApplet->warningBox(tr("File \"%1\" haven't been synced").arg(file.name));
+            return;
+        }
+        openFile(synced_path);
+        return;
+    }
+    QString cached_file = data_mgr_->getLocalCachedFile(repo_.id, fpath, file.id);
+    qDebug("cached_file is %s", cached_file.toUtf8().data());
+    if (!cached_file.isEmpty() && QFileInfo(cached_file).exists()) {
+        // double-checked the watch, since it might fails sometime
+        AutoUpdateManager::instance()->watchCachedFile(account_, repo_.id, fpath);
+        openFile(cached_file);
+        return;
+    } else {
+        if (TransferManager::instance()->getDownloadTask(repo_.id, fpath)) {
+            return;
+        }
+        AutoUpdateManager::instance()->removeWatch(
+            DataManager::getLocalCacheFilePath(repo_.id, fpath));
+        downloadFile(fpath);
+    }
+}
+
+void FileBrowserDialog::createDirectory(const QString &name)
+{
+    data_mgr_->createDirectory(repo_.id, ::pathJoin(current_path_, name));
+}
+
+void FileBrowserDialog::downloadFile(const QString& path)
+{
+    qDebug("begin to downloadfile is %s", path.toUtf8().data());
+    FileDownloadTask *task = data_mgr_->createDownloadTask(repo_.id, path);
+    connect(task, SIGNAL(finished(bool)), this, SLOT(onDownloadFinished(bool)));
+}
+
+void FileBrowserDialog::onGetDirentReupload(const SeafDirent& dirent)
+{
+    QString path = ::pathJoin(current_path_, dirent.name);
+    QString local_path = DataManager::getLocalCacheFilePath(repo_.id, path);
+    AutoUpdateManager::instance()->uploadFile(local_path);
+}
+
+void FileBrowserDialog::uploadFile(const QString& path, const QString& name,
+                                   bool overwrite)
+{
+    FileUploadTask *task =
+      data_mgr_->createUploadTask(repo_.id, current_path_, path, name, overwrite);
+    connect(task, SIGNAL(finished(bool)), this, SLOT(onUploadFinished(bool)));
+    FileBrowserProgressDialog *dialog = new FileBrowserProgressDialog(task, this);
+    task->start();
+
+    // set dialog attributes
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->setWindowModality(Qt::NonModal);
+    dialog->show();
+    dialog->raise();
+    dialog->activateWindow();
+}
+
+void FileBrowserDialog::uploadMultipleFile(const QStringList& names,
+                                           bool overwrite)
+{
+    if (names.empty())
+        return;
+    QString local_path;
+    QStringList fnames;
+    Q_FOREACH(const QString &name, names) {
+        const QFileInfo file = name;
+        if (file.isDir()) {
+            // a dir
+            uploadOrUpdateFile(name);
+        } else {
+            // a file
+            if (local_path.isEmpty()) {
+                local_path = file.path();
+                fnames.push_back(file.fileName());
+            } else if (file.path() == local_path) {
+                fnames.push_back(file.fileName());
+            } else {
+                qWarning(
+                    "upload multiple files: ignore file %s because it's not in "
+                    "the same directory",
+                    toCStr(file.absoluteFilePath()));
+            }
+        }
+    }
+
+    if (fnames.empty()) {
+        return;
+    }
+
+    FileUploadTask *task =
+        data_mgr_->createUploadMultipleTask(repo_.id, current_path_, local_path, fnames,
+                                            overwrite);
+    connect(task, SIGNAL(finished(bool)), this, SLOT(onUploadFinished(bool)));
+    FileBrowserProgressDialog *dialog = new FileBrowserProgressDialog(task, this);
+    task->start();
+
+    // set dialog attributes
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->setWindowModality(Qt::NonModal);
+    dialog->show();
+    dialog->raise();
+    dialog->activateWindow();
+}
+
+void FileBrowserDialog::uploadFileOrMkdir()
+{
+    // the menu shows in the right-down corner
+    upload_menu_->exec(upload_button_->mapToGlobal(
+        QPoint(upload_button_->width()-2, upload_button_->height()/2)));
+}
+
+void FileBrowserDialog::uploadOrUpdateFile(const QString& path)
+{
+    const QString name = ::getBaseName(path);
+
+    // ignore the confirm procedure for uploading directory, which is non-sense
+    if (QFileInfo(path).isDir())
+        return uploadFile(path, name);
+
+    // prompt a dialog to confirm to overwrite the current file
+    if (findConflict(name, table_model_->dirents())) {
+        QMessageBox::StandardButton ret = seafApplet->yesNoCancelBox(
+            tr("File %1 already exists.<br/>"
+               "Do you like to overwrite it?<br/>"
+               "<small>(Choose No to upload using an alternative name).</small>").arg(name),
+            this,
+            QMessageBox::Cancel);
+
+        if (ret == QMessageBox::Cancel) {
+            return;
+        } else if (ret == QMessageBox::Yes) {
+            // overwrite the file
+            uploadFile(path, name, true);
+            return;
+        }
+    }
+
+    // in other cases, use upload
+    uploadFile(path, name);
+}
+
+void FileBrowserDialog::uploadOrUpdateMutipleFile(const QStringList &paths)
+{
+    if (paths.size() == 1)
+        uploadOrUpdateFile(paths.front());
+    else
+        uploadMultipleFile(paths);
+}
+
+void FileBrowserDialog::onDownloadFinished(bool success)
+{
+    FileDownloadTask *task = qobject_cast<FileDownloadTask *>(sender());
+    QString _error;
+    if (task == NULL)
+        return;
+    if (success) {
+        if (!task->isSaveAsTask())
+            openFile(task->localFilePath());
+    } else {
+        if (repo_.encrypted &&
+            setPasswordAndRetry(task)) {
+            return;
+        }
+
+        if (task->error() == FileNetworkTask::TaskCanceled)
+            return;
+
+        if (task->httpErrorCode() == 404) {
+            _error = tr("File does not exist");
+        } else if (task->httpErrorCode() == 401) {
+            _error = tr("Authorization expired");
+        } else {
+            _error = task->errorString();
+        }
+        QString msg = tr("Failed to download file: %1").arg(_error);
+        seafApplet->warningBox(msg, this);
+
+        if (task->httpErrorCode() == 401) {
+            stack_->setCurrentIndex(INDEX_RELOGIN_VIEW);
+        }
+    }
+}
+
+void FileBrowserDialog::onUploadFinished(bool success)
+{
+    FileUploadTask *task = qobject_cast<FileUploadTask *>(sender());
+    QString _error;
+    if (task == NULL)
+        return;
+
+    if (!success) {
+        if (repo_.encrypted &&
+            setPasswordAndRetry(task)) {
+            return;
+        }
+
+        // always force a refresh for uploading directory
+        if (qobject_cast<FileUploadDirectoryTask*>(sender()))
+            forceRefresh();
+
+        if (task->error() == FileNetworkTask::TaskCanceled)
+            return;
+
+        if (task->httpErrorCode() == 403) {
+            _error = tr("Permission Error!");
+        } else if (task->httpErrorCode() == 404) {
+            _error = tr("Library/Folder not found.");
+        } else if (task->httpErrorCode() == 401) {
+            _error = tr("Authorization expired");
+        } else {
+            _error = task->errorString();
+        }
+        QString msg = tr("Failed to upload file %1: %2").arg(task->failedPath()).arg(_error);
+        qWarning("failed to upload %s",toCStr(QFileInfo(task->failedPath()).fileName()));
+        seafApplet->warningBox(msg, this);
+        if (task->httpErrorCode() == 401) {
+            stack_->setCurrentIndex(INDEX_RELOGIN_VIEW);
+        }
+        return;
+    }
+
+    QString local_path = task->localFilePath();
+    QStringList names;
+
+    // Upload Directory Task
+    if (qobject_cast<FileUploadDirectoryTask *>(sender())) {
+        const SeafDirent dir = SeafDirent::dir(task->name());
+        // TODO: insert the Item prior to the item where uploading occurs
+        table_model_->insertItem(0, dir);
+        updateFileCount();
+        return;
+    }
+
+    // Upload Multiple Task
+    FileUploadMultipleTask *multi_task = qobject_cast<FileUploadMultipleTask *>(sender());
+
+    if (multi_task == NULL) {
+      names.push_back(task->name());
+      local_path = QFileInfo(local_path).absolutePath();
+    } else {
+      names = multi_task->successfulNames();
+      local_path = QFileInfo(local_path).absoluteFilePath();
+    }
+
+    // require a forceRefresh if conflicting filename found
+    Q_FOREACH(const QString &name, names)
+    {
+        if (findConflict(name, table_model_->dirents())) {
+            forceRefresh();
+            return;
+        }
+    }
+
+    // add the items to tableview
+    Q_FOREACH(const QString &name, names) {
+        const QFileInfo file = QDir(local_path).filePath(name);
+        const SeafDirent dirent = SeafDirent::file(name, static_cast<quint64>(file.size()));
+        if (task->useUpload())
+            table_model_->appendItem(dirent);
+        else
+            table_model_->replaceItem(name, dirent);
+    }
+
+    if (stack_->currentIndex() == INDEX_EMPTY_VIEW) {
+        forceRefresh();
+    }
+
+    updateFileCount();
+}
+
+bool FileBrowserDialog::setPasswordAndRetry(FileNetworkTask *task)
+{
+    if (task->httpErrorCode() == 400) {
+        if (has_password_dialog_) {
+            return true;
+        }
+        has_password_dialog_ = true;
+        SetRepoPasswordDialog password_dialog(repo_, this);
+        if (password_dialog.exec() == QDialog::Accepted) {
+            if (task->type() == FileNetworkTask::Download)
+                downloadFile(task->path());
+            else
+                uploadOrUpdateFile(task->path());
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void FileBrowserDialog::goForward()
+{
+    QString path;
+    if (!forward_history_.empty()) {
+        path = forward_history_.pop();
+    }
+    backward_history_.push(current_path_);
+    enterPath(path);
+}
+
+void FileBrowserDialog::goBackward()
+{
+    QString path;
+    if (!backward_history_.empty()) {
+        path = backward_history_.pop();
+    }
+    forward_history_.push(current_path_);
+    enterPath(path);
+}
+
+void FileBrowserDialog::goHome()
+{
+    if (current_path_ == "/") {
+        return;
+    }
+    backward_history_.push(current_path_);
+    forward_history_.clear();
+    enterPath("/");
+}
+
+void FileBrowserDialog::updateTable(const QList<SeafDirent>& dirents)
+{
+    if (dirents.isEmpty()) {
+        table_model_->setDirents(QList<SeafDirent>());
+        stack_->setCurrentIndex(INDEX_TABLE_VIEW);
+    } else {
+        table_model_->setDirents(dirents);
+        stack_->setCurrentIndex(INDEX_TABLE_VIEW);
+    }
+
+    if (!forward_history_.empty()) {
+        forward_button_->setEnabled(true);
+    } else {
+        forward_button_->setEnabled(false);
+    }
+    if (!backward_history_.empty()) {
+        backward_button_->setEnabled(true);
+    } else {
+        backward_button_->setEnabled(false);
+    }
+    if (!current_readonly_) {
+        upload_button_->setEnabled(true);
+    }
+    gohome_action_->setEnabled(current_path_ != "/");
+    updateFileCount();
+}
+
+void FileBrowserDialog::chooseFileToUpload()
+{
+    QStringList paths = QFileDialog::getOpenFileNames(this, tr("Select a file to upload"), QDir::homePath());
+    if (paths.empty())
+        return;
+    uploadOrUpdateMutipleFile(paths);
+}
+
+void FileBrowserDialog::chooseDirectoryToUpload()
+{
+    QString path = QFileDialog::getExistingDirectory(this, tr("Select a directory to upload"), QDir::homePath());
+    if (path.isEmpty())
+        return;
+    uploadOrUpdateFile(path);
+}
+
+void FileBrowserDialog::onNavigatorClick(int id)
+{
+    // calculate the path
+    QString path = "/";
+    for(int i = 1; i <= id; i++)
+      path += current_lpath_[i] + "/";
+
+    backward_history_.push(current_path_);
+    forward_history_.clear();
+    enterPath(path);
+}
+
+void FileBrowserDialog::onGetDirentLock(const SeafDirent& dirent)
+{
+    data_mgr_->lockFile(repo_.id, ::pathJoin(current_path_, dirent.name), !dirent.is_locked);
+}
+
+void FileBrowserDialog::onGetDirentRename(const SeafDirent& dirent,
+                                          QString new_name)
+{
+    if (new_name.isEmpty()) {
+        new_name = seafApplet->getText(this, tr("Rename"),
+                   QObject::tr("Rename %1 to").arg(dirent.name),
+                   QLineEdit::Normal,
+                   dirent.name);
+        // trim the whites
+        new_name = new_name.trimmed();
+        // if cancelled or empty
+        if (new_name.isEmpty())
+            return;
+        // if no change
+        if (dirent.name == new_name)
+            return;
+    }
+    data_mgr_->renameDirent(repo_.id,
+                            ::pathJoin(current_path_, dirent.name),
+                            new_name,
+                            dirent.isFile());
+}
+
+void FileBrowserDialog::onGetDirentRemove(const SeafDirent& dirent)
+{
+    // if (seafApplet->yesOrNoBox(dirent.isFile() ?
+    //         tr("Do you really want to delete file \"%1\"?").arg(dirent.name) :
+    //         tr("Do you really want to delete folder \"%1\"?").arg(dirent.name), this, false))
+    data_mgr_->removeDirent(repo_.id, pathJoin(current_path_, dirent.name),
+                            dirent.isFile());
+}
+
+void FileBrowserDialog::onGetDirentRemove(const QList<const SeafDirent*> &dirents)
+{
+    if (!seafApplet->yesOrNoBox(tr("Do you really want to delete these items"), this, false))
+        return;
+
+    QStringList filenames;
+    foreach (const SeafDirent *dirent, dirents) {
+        filenames << dirent->name;
+    }
+    data_mgr_->removeDirents(repo_.id, current_path_, filenames);
+}
+
+void FileBrowserDialog::onGetDirentShare(const SeafDirent& dirent)
+{
+    data_mgr_->shareDirent(repo_.id,
+                           ::pathJoin(current_path_, dirent.name),
+                           dirent.isFile());
+}
+
+void FileBrowserDialog::onGetDirentShareToUserOrGroup(const SeafDirent& dirent,
+                                                bool to_group)
+{
+    PrivateShareDialog dialog(account_, repo_.id, repo_.name,
+                              ::pathJoin(current_path_, dirent.name), to_group,
+                              this);
+    dialog.exec();
+}
+
+void FileBrowserDialog::onGetDirentShareSeafile(const SeafDirent& dirent)
+{
+    QString repo_id = repo_.id;
+    QString email = account_.username;
+    QString path = ::pathJoin(current_path_, dirent.name);
+    if (dirent.isDir())
+        path += "/";
+    GetSmartLinkRequest *req = new GetSmartLinkRequest(account_, repo_id, path, dirent.isDir());
+    connect(req, SIGNAL(success(const QString&)),
+            this, SLOT(onGetSmartLinkSuccess(const QString&)));
+    connect(req, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetSmartLinkFailed(const ApiError&)));
+
+    req->send();
+}
+
+void FileBrowserDialog::onGetSmartLinkSuccess(const QString& smart_link)
+{
+    SeafileLinkDialog(smart_link, this).exec();
+}
+
+void FileBrowserDialog::onGetSmartLinkFailed(const ApiError& error)
+{
+    seafApplet->warningBox(tr("Failed to get link"));
+}
+
+void FileBrowserDialog::onDirectoryCreateSuccess(const QString &path)
+{
+    const QString name = QFileInfo(path).fileName();
+    // if no longer current level
+    if (::pathJoin(current_path_, name) != path)
+        return;
+    const SeafDirent dirent = SeafDirent::dir(name);
+    // TODO insert to the pos where the drop event triggered
+    table_model_->insertItem(0, dirent);
+    if (stack_->currentIndex() == INDEX_EMPTY_VIEW)
+        forceRefresh();
+
+    updateFileCount();
+}
+
+void FileBrowserDialog::onDirectoryCreateFailed(const ApiError&error)
+{
+    seafApplet->warningBox(tr("Create folder failed"), this);
+}
+
+void FileBrowserDialog::onFileLockSuccess(const QString& path, bool lock)
+{
+    const QString name = QFileInfo(path).fileName();
+    // if no longer current level
+    if (::pathJoin(current_path_, name) != path)
+        return;
+    const SeafDirent *old_dirent = NULL;
+    Q_FOREACH(const SeafDirent& dirent, table_model_->dirents())
+    {
+        if (dirent.name == name) {
+            old_dirent = &dirent;
+            break;
+        }
+    }
+    if (!old_dirent)
+        return;
+    SeafDirent new_dirent = *old_dirent;
+    new_dirent.is_locked = new_dirent.locked_by_me = lock;
+    new_dirent.lock_owner = account_.username;
+    new_dirent.lock_owner_name = account_.accountInfo.name;
+    table_model_->replaceItem(name, new_dirent);
+}
+
+void FileBrowserDialog::onFileLockFailed(const ApiError& error)
+{
+    seafApplet->warningBox(tr("Lock file failed"), this);
+}
+
+void FileBrowserDialog::onDirentRenameSuccess(const QString& path,
+                                              const QString& new_name)
+{
+    const QString name = QFileInfo(path).fileName();
+    // if no longer current level
+    if (::pathJoin(current_path_, name) != path)
+        return;
+    table_model_->renameItemNamed(name, new_name);
+}
+
+void FileBrowserDialog::onGetDirentUpdate(const SeafDirent& dirent)
+{
+    QString path = QFileDialog::getOpenFileName(this,
+        tr("Select a file to update %1").arg(dirent.name), QDir::homePath());
+    if (!path.isEmpty()) {
+        uploadFile(path, dirent.name, true);
+    }
+}
+
+void FileBrowserDialog::onDirentRenameFailed(const ApiError&error)
+{
+    seafApplet->warningBox(tr("Rename failed"), this);
+}
+
+void FileBrowserDialog::onDirentRemoveSuccess(const QString& path)
+{
+    const QString name = QFileInfo(path).fileName();
+    // if no longer current level
+    if (::pathJoin(current_path_, name) != path)
+        return;
+    table_model_->removeItemNamed(name);
+    updateFileCount();
+
+    if (table_model_->rowCount() == 0) {
+        stack_->setCurrentIndex(INDEX_TABLE_VIEW);
+    }
+}
+
+void FileBrowserDialog::onDirentRemoveFailed(const ApiError&error)
+{
+    seafApplet->warningBox(tr("Remove failed"), this);
+}
+
+void FileBrowserDialog::onDirentsRemoveSuccess(const QString& parent_path,
+                                               const QStringList& filenames)
+{
+    // if no longer current level
+    if (current_path_ != parent_path)
+        return;
+    foreach (const QString& name, filenames) {
+        // printf("removed file: %s\n", name.toUtf8().data());
+        table_model_->removeItemNamed(name);
+    }
+    updateFileCount();
+
+    if (table_model_->rowCount() == 0) {
+        stack_->setCurrentIndex(INDEX_TABLE_VIEW);
+    }
+}
+
+void FileBrowserDialog::onDirentsRemoveFailed(const ApiError&error)
+{
+    seafApplet->warningBox(tr("Remove failed"), this);
+}
+
+void FileBrowserDialog::onDirentShareSuccess(const QString &link)
+{
+    SharedLinkDialog(link, this).exec();
+}
+
+void FileBrowserDialog::onDirentShareFailed(const ApiError&error)
+{
+    seafApplet->warningBox(tr("Share failed"), this);
+}
+
+void FileBrowserDialog::onFileAutoUpdated(const QString& repo_id, const QString& path)
+{
+    if (repo_id == repo_.id && path == current_path_) {
+        forceRefresh();
+    }
+}
+
+void FileBrowserDialog::onCancelDownload(const SeafDirent& dirent)
+{
+    TransferManager::instance()->cancelDownload(repo_.id,
+        ::pathJoin(current_path_, dirent.name));
+}
+
+
+void FileBrowserDialog::done(int retval)
+{
+    emit aboutToClose();
+    QDialog::done(retval);
+}
+
+bool FileBrowserDialog::hasFilesToBePasted() {
+    return !file_names_to_be_pasted_.empty();
+}
+
+void FileBrowserDialog::setFilesToBePasted(bool is_copy, const QStringList &file_names)
+{
+    is_copyed_when_pasted_ = is_copy;
+    dir_path_to_be_pasted_from_ = current_path_;
+    file_names_to_be_pasted_ = file_names;
+    repo_id_to_be_pasted_from_ = repo_.id;
+    account_to_be_pasted_from_ = account_;
+}
+
+void FileBrowserDialog::onGetDirentsPaste()
+{
+    if (repo_id_to_be_pasted_from_ == repo_.id) {
+        if (current_path_ == dir_path_to_be_pasted_from_) {
+            seafApplet->warningBox(tr("Cannot paste files from the same folder"), this);
+            return;
+        }
+
+        if (file_names_to_be_pasted_.isEmpty()) {
+            return;
+        }
+
+        // Paste /a/ into /a/b/ is not allowed
+        for (const QString& name : file_names_to_be_pasted_) {
+            const QString file_path_to_be_pasted =
+                appendTrailingSlash(::pathJoin(dir_path_to_be_pasted_from_, name));
+            if (appendTrailingSlash(current_path_).startsWith(file_path_to_be_pasted)) {
+                seafApplet->warningBox(tr("Cannot paste the folder to its subfolder"), this);
+                return;
+            }
+        }
+    }
+
+    if (is_copyed_when_pasted_)
+        data_mgr_->copyDirents(repo_id_to_be_pasted_from_,
+                               dir_path_to_be_pasted_from_,
+                               file_names_to_be_pasted_,
+                               repo_.id,
+                               current_path_);
+    else
+        data_mgr_->moveDirents(repo_id_to_be_pasted_from_,
+                               dir_path_to_be_pasted_from_,
+                               file_names_to_be_pasted_,
+                               repo_.id,
+                               current_path_);
+}
+
+void FileBrowserDialog::onDirentsCopySuccess()
+{
+    forceRefresh();
+}
+
+void FileBrowserDialog::onDirentsCopyFailed(const ApiError& error)
+{
+    seafApplet->warningBox(tr("Copy failed"), this);
+}
+
+void FileBrowserDialog::onDirentsMoveSuccess()
+{
+    file_names_to_be_pasted_.clear();
+    FileBrowserDialog *dialog =
+        FileBrowserManager::getInstance()->getDialog(account_to_be_pasted_from_, repo_id_to_be_pasted_from_);
+    if (dialog != NULL && dialog->current_path_ == dir_path_to_be_pasted_from_) {
+        dialog->forceRefresh();
+    }
+
+    msleep(500);
+    forceRefresh();
+}
+
+void FileBrowserDialog::onDirentsMoveFailed(const ApiError& error)
+{
+    seafApplet->warningBox(tr("Move failed"), this);
+}
+
+void FileBrowserDialog::onGetSyncSubdirectory(const QString &folder_name)
+{
+    data_mgr_->createSubrepo(folder_name, repo_.id, ::pathJoin(current_path_, folder_name));
+}
+
+void FileBrowserDialog::onDeleteLocalVersion(const SeafDirent &dirent)
+{
+    QString fpath = ::pathJoin(current_path_, dirent.name);
+    QString cached_file = data_mgr_->getLocalCachedFile(repo_.id, fpath, dirent.id);
+    if (!cached_file.isEmpty() && QFileInfo(cached_file).exists()) {
+        QFile::remove(cached_file);
+        return;
+    }
+}
+
+void FileBrowserDialog::onLocalVersionSaveAs(const SeafDirent &dirent)
+{
+    static QDir download_dir(defaultDownloadDir());
+    if (!download_dir.exists())
+       download_dir = QDir::home();
+
+     QString fpath = ::pathJoin(current_path_, dirent.name);
+     QString cached_file = data_mgr_->getLocalCachedFile(repo_.id, fpath, dirent.id);
+     if (!cached_file.isEmpty() && QFileInfo(cached_file).exists()) {
+         QString local_path = QFileDialog::getSaveFileName(this, tr("Enter name of file to save to..."), download_dir.filePath(dirent.name));
+         QFile::copy(cached_file, local_path);
+         return;
+     }
+}
+
+void FileBrowserDialog::onOpenLocalCacheFolder()
+{
+     QString folder =
+             ::pathJoin(data_mgr_->getRepoCacheFolder(repo_.id), current_path_);
+     if (!::createDirIfNotExists(folder)) {
+         seafApplet->warningBox(tr("Unable to create cache folder"), this);
+         return;
+     }
+     if (!QDesktopServices::openUrl(QUrl::fromLocalFile(folder)))
+         seafApplet->warningBox(tr("Unable to open cache folder"), this);
+}
+
+void FileBrowserDialog::onCreateSubrepoSuccess(const ServerRepo &repo)
+{
+    // if we have not synced before
+    bool has_local = false;
+    if (seafApplet->rpcClient()->hasLocalRepo(repo.id)) {
+        has_local = true;
+    } else {
+        // if we have not synced, do it
+        DownloadRepoDialog dialog(account_, repo,
+                                  repo.encrypted ? data_mgr_->repoPassword(repo_.id) : QString(), this);
+
+        has_local = dialog.exec() == QDialog::Accepted;
+    }
+
+    if (has_local)
+        RepoService::instance()->saveSyncedSubfolder(repo);
+}
+
+void FileBrowserDialog::onCreateSubrepoFailed(const ApiError&error)
+{
+    seafApplet->warningBox(tr("Create library failed!"), this);
+}
+
+void FileBrowserDialog::fixUploadButtonHighlightStyle()
+{
+    fixUploadButtonStyle(true);
+}
+
+void FileBrowserDialog::fixUploadButtonNonHighlightStyle()
+{
+    fixUploadButtonStyle(false);
+}
+
+void FileBrowserDialog::fixUploadButtonStyle(bool highlighted)
+{
+    if (highlighted) {
+        upload_button_->setStyleSheet("FileBrowserDialog QToolButton#uploadButton {"
+                                      "background: #DFDFDF; padding: 3px;"
+                                      "margin-left: 12px; border-radius: 2px;}");
+    } else {
+        // XX: underMouse() return true even if the upload button is not under mouse!
+        //
+        // if (upload_button_->underMouse()) {
+        //     return;
+        // }
+        upload_button_->setStyleSheet("FileBrowserDialog QToolButton#uploadButton {"
+                                      "background: #F5F5F7; padding: 0px;"
+                                      "margin-left: 15px;}");
+    }
+}
+
+void FileBrowserDialog::onAccountInfoUpdated()
+{
+    forceRefresh();
+}
+
+void FileBrowserDialog::doSearch(const QString &keyword)
+{
+    // make it search utf-8 charcters
+    if (keyword.toUtf8().size() < 3) {
+        stack_->setCurrentIndex(INDEX_TABLE_VIEW);
+        updateFileCount();
+        return;
+    }
+
+    // save for doRealSearch
+    search_text_last_modified_ = QDateTime::currentMSecsSinceEpoch();
+}
+
+void FileBrowserDialog::doRealSearch()
+{
+    // not modified
+    if (search_text_last_modified_ == 0)
+        return;
+    // modified too fast
+    if (QDateTime::currentMSecsSinceEpoch() - search_text_last_modified_ <= 300)
+        return;
+
+    if (!account_.isValid())
+        return;
+
+    if (search_request_) {
+        // search_request_->abort();
+        search_request_->deleteLater();
+        search_request_ = NULL;
+    }
+
+    stack_->setCurrentIndex(INDEX_LOADING_VIEW);
+
+    search_request_ = new FileSearchRequest(account_, search_bar_->text(), kAllPage, kPerPageCount, repo_.id);
+    connect(search_request_, SIGNAL(success(const std::vector<FileSearchResult>&, bool, bool)),
+            this, SLOT(onSearchSuccess(const std::vector<FileSearchResult>&, bool, bool)));
+    connect(search_request_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onSearchFailed(const ApiError&)));
+
+    search_request_->send();
+
+    // reset
+    search_text_last_modified_ = 0;
+}
+
+void FileBrowserDialog::onSearchSuccess(const std::vector<FileSearchResult>& results,
+                                bool is_loading_more,
+                                bool has_more)
+{
+    search_model_->setSearchResult(results);
+    stack_->setCurrentIndex(INDEX_SEARCH_VIEW);
+    updateFileCount();
+}
+
+void FileBrowserDialog::onSearchFailed(const ApiError& error)
+{
+    stack_->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+}
+
+
+DataManagerNotify::DataManagerNotify(const QString &repo_id)
+    :repo_id_(repo_id)
+{
+    data_mgr_ = seafApplet->dataManager();
+    connect(data_mgr_, SIGNAL(getDirentsSuccess(bool, const QList<SeafDirent>&, const QString&)),
+            this, SLOT(onGetDirentsSuccess(bool, const QList<SeafDirent>&, const QString&)));
+    connect(data_mgr_, SIGNAL(getDirentsFailed(const ApiError&, const QString&)),
+            this, SLOT(onGetDirentsFailed(const ApiError&, const QString&)));
+    connect(data_mgr_, SIGNAL(createDirectorySuccess(const QString&, const QString&)),
+            this, SLOT(onDirectoryCreateSuccess(const QString&, const QString&)));
+    connect(data_mgr_, SIGNAL(lockFileSuccess(const QString&, bool, const QString&)),
+            this, SLOT(onFileLockSuccess(const QString&, bool, const QString&)));
+    connect(data_mgr_, SIGNAL(renameDirentSuccess(const QString&, const QString&, const QString&)),
+            this, SLOT(onDirentRenameSuccess(const QString&, const QString&, const QString&)));
+    connect(data_mgr_, SIGNAL(removeDirentSuccess(const QString&, const QString&)),
+            this, SLOT(onDirentRemoveSuccess(const QString&, const QString&)));
+    connect(data_mgr_, SIGNAL(removeDirentsSuccess(const QString&, const QStringList&, const QString&)),
+            this, SLOT(onDirentsRemoveSuccess(const QString&, const QStringList&, const QString&)));
+    connect(data_mgr_, SIGNAL(shareDirentSuccess(const QString&, const QString&)),
+            this, SLOT(onDirentShareSuccess(const QString&, const QString&)));
+    connect(data_mgr_, SIGNAL(createSubrepoSuccess(const ServerRepo &, const QString&)),
+            this, SLOT(onCreateSubrepoSuccess(const ServerRepo &, const QString&)));
+    connect(data_mgr_, SIGNAL(copyDirentsSuccess(const QString&)),
+            this, SLOT(onDirentsCopySuccess(const QString&)));
+    connect(data_mgr_, SIGNAL(moveDirentsSuccess(const QString&)),
+            this, SLOT(onDirentsMoveSuccess(const QString&)));
+}
+
+void DataManagerNotify::onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents, const QString& repo_id)
+{
+    if (repo_id == repo_id_) {
+        emit getDirentsSuccess(current_readonly, dirents);
+    }
+}
+
+void DataManagerNotify::onGetDirentsFailed(const ApiError &error, const QString &repo_id)
+{
+    if (repo_id == repo_id_) {
+        emit getDirentsFailed(error);
+    }
+}
+
+void DataManagerNotify::onDirectoryCreateSuccess(const QString &path, const QString &repo_id)
+{
+    if (repo_id == repo_id_) {
+        emit createDirectorySuccess(path);
+    }
+}
+
+void DataManagerNotify::onFileLockSuccess(const QString &path, bool lock, const QString &repo_id)
+{
+    if (repo_id == repo_id_) {
+        emit lockFileSuccess(path, lock);
+    }
+}
+
+void DataManagerNotify::onDirentRenameSuccess(const QString &path, const QString &new_name, const QString &repo_id)
+{
+    if (repo_id == repo_id_) {
+        emit renameDirentSuccess(path, new_name);
+    }
+}
+
+void DataManagerNotify::onDirentRemoveSuccess(const QString &path, const QString &repo_id)
+{
+    if (repo_id == repo_id_) {
+        emit removeDirentSuccess(path);
+    }
+}
+
+void DataManagerNotify::onDirentsRemoveSuccess(const QString &parent_path, const QStringList &filenames, const QString &repo_id)
+{
+    if (repo_id == repo_id_) {
+        emit removeDirentsSuccess(parent_path, filenames);
+    }
+}
+
+void DataManagerNotify::onDirentShareSuccess(const QString &link, const QString &repo_id)
+{
+    if (repo_id == repo_id_) {
+        emit shareDirentSuccess(link);
+    }
+}
+
+void DataManagerNotify::onCreateSubrepoSuccess(const ServerRepo &repo, const QString& repo_id)
+{
+    if (repo_id == repo_id_) {
+        emit createSubrepoSuccess(repo);
+    }
+}
+
+void DataManagerNotify::onDirentsCopySuccess(const QString& dst_repo_id)
+{
+    if (dst_repo_id == repo_id_) {
+        emit copyDirentsSuccess();
+    }
+}
+
+void DataManagerNotify::onDirentsMoveSuccess(const QString& dst_repo_id)
+{
+    if (dst_repo_id == repo_id_) {
+        emit moveDirentsSuccess();
+    }
+}
diff --git a/src/filebrowser/file-browser-dialog.h b/src/filebrowser/file-browser-dialog.h
new file mode 100644 (file)
index 0000000..cc4b7e1
--- /dev/null
@@ -0,0 +1,295 @@
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_DIALOG_H
+#define SEAFILE_CLIENT_FILE_BROWSER_DIALOG_H
+
+#include <QStack>
+#include <QDialog>
+
+#include "account.h"
+#include "api/server-repo.h"
+#include "file-browser-search-tab.h"
+#include "ui/search-bar.h"
+
+class QToolBar;
+class QToolButton;
+class QAction;
+class QStackedWidget;
+class QLineEdit;
+class QLabel;
+class QButtonGroup;
+class QMenu;
+class QAction;
+class QSizeGrip;
+class QHBoxLayout;
+
+class ApiError;
+class FileTableView;
+class FileTableModel;
+class SeafDirent;
+class GetDirentsRequest;
+class FileBrowserCache;
+class DataManager;
+class DataManagerNotify;
+class FileNetworkTask;
+class FileBrowserManager;
+
+class SearchBar;
+class FileBrowserSearchItemDelegate;
+class FileBrowserSearchView;
+class FileBrowserSearchModel;
+struct FileSearchResult;
+class FileSearchRequest;
+
+/**
+ * This dialog is used when the user clicks on a repo not synced yet.
+ *
+ * The user can browse the files of this repo. When he clicks on a file, the
+ * file would be downloaded to a temporary location. If the user modifies the
+ * downloaded file, the new version would be automatically uploaded to the
+ * server.
+ *
+ */
+class FileBrowserDialog : public QDialog
+                          // public Ui::FileBrowserDialog
+{
+    Q_OBJECT
+    friend class FileBrowserManager;
+public:
+    FileBrowserDialog(const Account &account, const ServerRepo& repo,
+                      const QString &path, QWidget *parent=0);
+    ~FileBrowserDialog();
+
+    // only accept path ends with "/"
+    void enterPath(const QString& path);
+    void onGetDirentReupload(const SeafDirent& dirent);
+    void onOpenLocalCacheFolder();
+
+    friend class FileTableView;
+    friend class FileTableModel;
+signals:
+    void aboutToClose();
+
+private slots:
+    void init();
+
+    void onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents);
+    void onGetDirentsFailed(const ApiError& error);
+    void onMkdirButtonClicked();
+    void fetchDirents();
+    void onDirentClicked(const SeafDirent& dirent);
+    void onDirentSaveAs(const QList<const SeafDirent*>& dirents);
+    void onRefresh();
+    void goForward();
+    void goBackward();
+    void goHome();
+    void chooseFileToUpload();
+    void chooseDirectoryToUpload();
+    void onDownloadFinished(bool success);
+    void onUploadFinished(bool success);
+
+    // prompt a menu for user to choose a upload action
+    void uploadFileOrMkdir();
+
+    // prompt a dialog for user to choose whether upload or update
+    void uploadOrUpdateFile(const QString& path);
+    void uploadOrUpdateMutipleFile(const QStringList& paths);
+
+    void onNavigatorClick(int id);
+
+    void onGetDirentLock(const SeafDirent& dirent);
+    void onGetDirentRename(const SeafDirent& dirent, QString new_name = QString());
+    void onGetDirentRemove(const SeafDirent& dirent);
+    void onGetDirentRemove(const QList<const SeafDirent*> &dirents);
+    void onGetDirentShare(const SeafDirent& dirent);
+    void onGetDirentShareToUserOrGroup(const SeafDirent& dirent, bool to_group);
+    void onGetDirentShareSeafile(const SeafDirent& dirent);
+    void onGetDirentUpdate(const SeafDirent& dirent);
+    void onGetDirentsPaste();
+    void onGetSyncSubdirectory(const QString &folder_name);
+    void onCancelDownload(const SeafDirent& dirent);
+
+    void onDeleteLocalVersion(const SeafDirent& dirent);
+    void onLocalVersionSaveAs(const SeafDirent& dirent);
+    void onDirectoryCreateSuccess(const QString& path);
+    void onDirectoryCreateFailed(const ApiError& error);
+    void onFileLockSuccess(const QString& path, bool lock);
+    void onFileLockFailed(const ApiError& error);
+    void onDirentRenameSuccess(const QString& path, const QString& new_name);
+    void onDirentRenameFailed(const ApiError& error);
+    void onDirentRemoveSuccess(const QString& path);
+    void onDirentRemoveFailed(const ApiError& error);
+
+    void onDirentsRemoveSuccess(const QString& parent_path,
+                                const QStringList& filenames);
+    void onDirentsRemoveFailed(const ApiError& error);
+
+    void onDirentShareSuccess(const QString& link);
+    void onDirentShareFailed(const ApiError& error);
+
+    void onDirentsCopySuccess();
+    void onDirentsCopyFailed(const ApiError& error);
+    void onDirentsMoveSuccess();
+    void onDirentsMoveFailed(const ApiError& error);
+
+    void onCreateSubrepoSuccess(const ServerRepo& repo);
+    void onCreateSubrepoFailed(const ApiError& error);
+
+    void onFileAutoUpdated(const QString& repo_id, const QString& path);
+
+    void fixUploadButtonStyle(bool highlighted);
+    void fixUploadButtonNonHighlightStyle();
+    void fixUploadButtonHighlightStyle();
+
+    void onAccountInfoUpdated();
+
+    //search
+    void doSearch(const QString& keyword);
+    void doRealSearch();
+    void onSearchSuccess(const std::vector<FileSearchResult>& results,
+                         bool is_loading_more,
+                         bool has_more);
+    void onSearchFailed(const ApiError& error);
+
+    void onGetSmartLinkSuccess(const QString& smart_link);
+    void onGetSmartLinkFailed(const ApiError& error);
+private:
+    Q_DISABLE_COPY(FileBrowserDialog)
+
+    void done(int retval);
+    bool hasFilesToBePasted();
+    void setFilesToBePasted(bool is_copy, const QStringList &file_names);
+
+    void createToolBar();
+    void createStatusBar();
+    void createFileTable();
+    void createLoadingFailedView();
+    void createEmptyView();
+    void showLoading();
+    void updateTable(const QList<SeafDirent>& dirents);
+    void createDirectory(const QString &name);
+    void downloadFile(const QString& path);
+    void uploadFile(const QString& path, const QString& name,
+                    bool overwrite = false);
+    void uploadMultipleFile(const QStringList& paths, bool overwrite = false);
+
+    void onDirClicked(const SeafDirent& dirent);
+    void onFileClicked(const SeafDirent& dirent);
+
+    void fetchDirents(bool force_refresh);
+
+    void updateFileCount();
+
+    void forceRefresh();
+
+    bool setPasswordAndRetry(FileNetworkTask *task);
+
+    bool eventFilter(QObject *obj, QEvent *event);
+    bool handleDragDropEvent(QObject *obj, QEvent *event);
+
+    const Account account_;
+    const ServerRepo repo_;
+
+    // current path
+    QString current_path_;
+    QStringList current_lpath_;
+    bool current_readonly_;
+    QStack<QString> forward_history_;
+    QStack<QString> backward_history_;
+
+    //search
+    QTimer *search_timer_;
+    FileSearchRequest *search_request_;
+    qint64 search_text_last_modified_;
+
+    // copy-paste related items between different instances of FileBrowserDialog
+    static QStringList file_names_to_be_pasted_;
+    static QString dir_path_to_be_pasted_from_;
+    static QString repo_id_to_be_pasted_from_;
+    static Account account_to_be_pasted_from_;
+    static bool is_copyed_when_pasted_;
+
+    QLabel *brand_label_;
+    QPushButton *minimize_button_;
+    QPushButton *close_button_;
+    QPoint old_pos_;
+
+    // top toolbar
+    QToolBar *toolbar_;
+    QToolBar *search_toolbar_;
+    QToolButton *backward_button_;
+    QToolButton *forward_button_;
+    QButtonGroup *path_navigator_;
+    QList<QLabel*> path_navigator_separators_;
+    QAction *gohome_action_;
+
+    // status toolbar
+    QWidget *status_bar_;
+    QHBoxLayout *status_layout_;
+    QToolButton *upload_button_;
+    QMenu *upload_menu_;
+    QAction *upload_file_action_;
+    QAction *upload_directory_action_;
+    QAction *mkdir_action_;
+    QLabel *details_label_;
+    QToolButton *refresh_button_;
+
+    // others
+    QStackedWidget *stack_;
+    QWidget *loading_view_;
+    QLabel *loading_failed_view_;
+    QWidget *relogin_view_;
+    QLabel *empty_view_;
+    FileTableView *table_view_;
+    FileTableModel *table_model_;
+
+    SearchBar *search_bar_;
+    FileBrowserSearchItemDelegate *search_delegate_;
+    FileBrowserSearchView *search_view_;
+    FileBrowserSearchModel *search_model_;
+
+    DataManager *data_mgr_;
+    DataManagerNotify *data_mgr_notify_;
+
+    // Avoid showing multiple SetRepoPasswordDialog
+    bool has_password_dialog_;
+};
+
+class DataManagerNotify : public QObject {
+    Q_OBJECT
+public:
+    DataManagerNotify(const QString& repo_id);
+    ~DataManagerNotify(){};
+signals:
+    void getDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents);
+    void getDirentsFailed(const ApiError& error);
+    void createDirectorySuccess(const QString& path);
+    void lockFileSuccess(const QString& path, bool lock);
+    void renameDirentSuccess(const QString& path, const QString& new_name);
+    void removeDirentSuccess(const QString& path);
+    void removeDirentsSuccess(const QString& parent_path, const QStringList& filenames);
+    void shareDirentSuccess(const QString& link);
+    void createSubrepoSuccess(const ServerRepo &repo);
+    void copyDirentsSuccess();
+    void moveDirentsSuccess();
+
+private slots:
+    void onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents, const QString& repo_id);
+    void onGetDirentsFailed(const ApiError& error, const QString& repo_id);
+    void onDirectoryCreateSuccess(const QString& path, const QString& repo_id);
+    void onFileLockSuccess(const QString& path, bool lock, const QString& repo_id);
+    void onDirentRenameSuccess(const QString& path, const QString& new_name, const QString& repo_id);
+    void onDirentRemoveSuccess(const QString& path, const QString& repo_id);
+    void onDirentsRemoveSuccess(const QString& parent_path,
+                                const QStringList& filenames,
+                                const QString& repo_id);
+    void onDirentShareSuccess(const QString& link, const QString& repo_id);
+    void onCreateSubrepoSuccess(const ServerRepo& repo, const QString& repo_id);
+    void onDirentsCopySuccess(const QString& dst_repo_id);
+    void onDirentsMoveSuccess(const QString& dst_repo_id);
+
+private:
+    DataManager *data_mgr_;
+    QString repo_id_;
+
+};
+
+#endif  // SEAFILE_CLIENT_FILE_BROWSER_DIALOG_H
diff --git a/src/filebrowser/file-browser-manager.cpp b/src/filebrowser/file-browser-manager.cpp
new file mode 100644 (file)
index 0000000..a2a8ef5
--- /dev/null
@@ -0,0 +1,118 @@
+#include "file-browser-manager.h"
+
+#include <QApplication>
+#include <QDesktopWidget>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+
+#include "file-browser-dialog.h"
+
+namespace {
+}
+
+FileBrowserManager *FileBrowserManager::instance_ = NULL;
+
+FileBrowserManager::FileBrowserManager() : QObject()
+{
+    // We use the accountAboutToRelogin signal instead of the
+    // accountRequireRelogin signal because other components are already
+    // connected to the the latter and may prompt a re-login dialog which would
+    // delay the call to our slots.
+    connect(seafApplet->accountManager(),
+            SIGNAL(accountAboutToRelogin(const Account&)),
+            this,
+            SLOT(closeAllDialogByAccount(const Account&)));
+
+    connect(seafApplet->accountManager(), SIGNAL(beforeAccountSwitched()),
+            this, SLOT(closeAllDialogs()));
+}
+
+
+FileBrowserDialog *FileBrowserManager::openOrActivateDialog(const Account &account, const ServerRepo &repo, const QString &path)
+{
+    FileBrowserDialog *dialog = getDialog(account, repo.id);
+    QString fixed_path = path;
+    if (!fixed_path.startsWith("/")) {
+        fixed_path = "/" + fixed_path;
+    }
+    if (!fixed_path.endsWith("/")) {
+        fixed_path += "/";
+    }
+    if (dialog == NULL) {
+        dialog = new FileBrowserDialog(account, repo, fixed_path);
+        QRect screen = QApplication::desktop()->screenGeometry();
+        dialog->setAttribute(Qt::WA_DeleteOnClose, true);
+        dialog->show();
+        dialog->move(screen.center() - dialog->rect().center());
+        dialogs_.push_back(dialog);
+        connect(dialog, SIGNAL(aboutToClose()), this, SLOT(onAboutToClose()));
+    } else if (!path.isEmpty()) {
+        dialog->enterPath(fixed_path);
+    }
+    dialog->raise();
+    dialog->activateWindow();
+    return dialog;
+}
+
+FileBrowserDialog *FileBrowserManager::getDialog(const Account &account, const QString &repo_id)
+{
+    // printf ("Get dialog: current %u CFB\n", dialogs_.size());
+    // search and find if dialog registered
+    for (int i = 0; i < dialogs_.size() ; i++)
+        if (dialogs_[i]->account_ == account &&
+            dialogs_[i]->repo_.id == repo_id) {
+            return dialogs_[i];
+        }
+    // not found
+    return NULL;
+}
+
+void FileBrowserManager::closeAllDialogByAccount(const Account& account)
+{
+    // printf ("closeAllDialogByAccount is called\n");
+
+    // Close all dialogs for the given account, e.g. when logging out or
+    // deleteing an account.
+
+    // Note: DO NOT remove close the dialog while iterating the dialogs list,
+    // because close the dialog would make it removed from the list (through the
+    // onAboutToClose signal). Instead we first collect the matched dialogs into
+    // a temporary list, then close them one by one.
+    QList<FileBrowserDialog *> dialogs_for_account;
+    foreach (FileBrowserDialog *dialog, dialogs_)
+    {
+        if (dialog->account_ == account) {
+            dialogs_for_account.push_back(dialog);
+        }
+    }
+
+    foreach (FileBrowserDialog *dialog, dialogs_for_account)
+    {
+        dialog->close();
+        // printf ("closed one CFB\n");
+    }
+}
+
+void FileBrowserManager::onAboutToClose()
+{
+    // printf ("got onAboutToClose\n");
+    FileBrowserDialog *dialog = qobject_cast<FileBrowserDialog*>(sender());
+    if (!dialog)
+      return;
+    dialogs_.removeOne(dialog);
+}
+
+void FileBrowserManager::closeAllDialogs()
+{
+    QList<FileBrowserDialog *> dialogs_for_account;
+    foreach (FileBrowserDialog *dialog, dialogs_)
+    {
+        dialogs_for_account.push_back(dialog);
+    }
+
+    foreach (FileBrowserDialog *dialog, dialogs_for_account)
+    {
+        dialog->close();
+    }
+}
diff --git a/src/filebrowser/file-browser-manager.h b/src/filebrowser/file-browser-manager.h
new file mode 100644 (file)
index 0000000..e1cf550
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_MANAGER_H
+#define SEAFILE_CLIENT_FILE_BROWSER_MANAGER_H
+#include <QObject>
+#include <QList>
+#include "api/server-repo.h"
+#include "account.h"
+
+class FileBrowserDialog;
+
+class FileBrowserManager : public QObject {
+  Q_OBJECT
+public:
+  static FileBrowserManager* getInstance() {
+    if (!instance_) {
+        static FileBrowserManager instance;
+        instance_ = &instance;
+    }
+    return instance_;
+  }
+
+  FileBrowserDialog *openOrActivateDialog(const Account &account, const ServerRepo &repo, const QString &path = "/");
+
+  FileBrowserDialog *getDialog(const Account &account, const QString &repo_id);
+
+public slots:
+  void closeAllDialogByAccount(const Account &account);
+
+private slots:
+  void onAboutToClose();
+  void closeAllDialogs();
+
+private:
+  FileBrowserManager(const FileBrowserManager*); // DELETED
+  FileBrowserManager& operator=(const FileBrowserManager*); // DELETED
+
+  FileBrowserManager();
+  static FileBrowserManager *instance_;
+  QList<FileBrowserDialog*> dialogs_;
+};
+
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_MANAGER_H
diff --git a/src/filebrowser/file-browser-requests.cpp b/src/filebrowser/file-browser-requests.cpp
new file mode 100644 (file)
index 0000000..87aeae0
--- /dev/null
@@ -0,0 +1,458 @@
+#include "file-browser-requests.h"
+
+#include <jansson.h>
+#include <QtNetwork>
+#include <QScopedPointer>
+
+#include "account.h"
+#include "api/api-error.h"
+#include "seaf-dirent.h"
+#include "utils/utils.h"
+
+namespace {
+
+const char kGetDirentsUrl[] = "api2/repos/%1/dir/";
+const char kGetFilesUrl[] = "api2/repos/%1/file/";
+const char kGetFileSharedLinkUrl[] = "api2/repos/%1/file/shared-link/";
+const char kGetFileUploadUrl[] = "api2/repos/%1/upload-link/";
+const char kGetFileUpdateUrl[] = "api2/repos/%1/update-link/";
+const char kGetStarredFilesUrl[] = "api2/starredfiles/";
+const char kFileOperationCopy[] = "api2/repos/%1/fileops/copy/";
+const char kFileOperationMove[] = "api2/repos/%1/fileops/move/";
+const char kRemoveDirentsURL[] = "api2/repos/%1/fileops/delete/";
+const char kGetFileUploadedBytesUrl[] = "api/v2.1/repos/%1/file-uploaded-bytes/";
+const char kGetSmartLink[] = "api/v2.1/smart-link/";
+//const char kGetFileFromRevisionUrl[] = "api2/repos/%1/file/revision/";
+//const char kGetFileDetailUrl[] = "api2/repos/%1/file/detail/";
+//const char kGetFileHistoryUrl[] = "api2/repos/%1/file/history/";
+
+} // namespace
+
+
+GetDirentsRequest::GetDirentsRequest(const Account& account,
+                                     const QString& repo_id,
+                                     const QString& path)
+    : SeafileApiRequest (account.getAbsoluteUrl(QString(kGetDirentsUrl).arg(repo_id)),
+                         SeafileApiRequest::METHOD_GET, account.token),
+      repo_id_(repo_id), path_(path), readonly_(false)
+{
+    setUrlParam("p", path);
+}
+
+void GetDirentsRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    QString dir_id = reply.rawHeader("oid");
+    if (dir_id.length() != 40) {
+        emit failed(ApiError::fromHttpError(500), repo_id_);
+        return;
+    }
+    // this extra header column only supported from v4.2 seahub
+    readonly_ = reply.rawHeader("dir_perm") == "r";
+
+    json_t *root = parseJSON(reply, &error);
+    if (!root) {
+        qDebug("GetDirentsRequest: failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError(), repo_id_);
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QList<SeafDirent> dirents;
+    dirents = SeafDirent::listFromJSON(json.data(), &error);
+    emit success(readonly_, dirents, repo_id_);
+}
+
+GetFileDownloadLinkRequest::GetFileDownloadLinkRequest(const Account &account,
+                                                       const QString &repo_id,
+                                                       const QString &path)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kGetFilesUrl).arg(repo_id)),
+          SeafileApiRequest::METHOD_GET, account.token)
+{
+    setUrlParam("p", path);
+}
+
+void GetFileDownloadLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+    QString reply_content(reply.readAll());
+    QString oid;
+
+    if (reply.hasRawHeader("oid"))
+        oid = reply.rawHeader("oid");
+
+    do {
+        if (reply_content.size() <= 2)
+            break;
+        reply_content.remove(0, 1);
+        reply_content.chop(1);
+        QUrl new_url(reply_content);
+
+        if (!new_url.isValid())
+            break;
+
+        file_id_ = oid;
+        emit success(reply_content);
+        return;
+    } while (0);
+    emit failed(ApiError::fromHttpError(500));
+}
+
+GetSharedLinkRequest::GetSharedLinkRequest(const Account &account,
+                                           const QString &repo_id,
+                                           const QString &path,
+                                           bool is_file)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kGetFileSharedLinkUrl).arg(repo_id)),
+          SeafileApiRequest::METHOD_PUT, account.token), repo_id_(repo_id)
+{
+    setFormParam("type", is_file ? "f" : "d");
+    setFormParam("p", path);
+}
+
+void GetSharedLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+    QString reply_content(reply.rawHeader("Location"));
+
+    emit success(reply_content, repo_id_);
+}
+
+CreateDirectoryRequest::CreateDirectoryRequest(const Account &account,
+                                               const QString &repo_id,
+                                               const QString &path,
+                                               bool create_parents)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kGetDirentsUrl).arg(repo_id)),
+          SeafileApiRequest::METHOD_POST, account.token),
+      repo_id_(repo_id), path_(path), create_parents_(create_parents)
+{
+    setUrlParam("p", path);
+
+    setFormParam("operation", "mkdir");
+    setFormParam("create_parents", create_parents ? "true" : "false");
+}
+
+void CreateDirectoryRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success(repo_id_);
+}
+
+GetFileUploadLinkRequest::GetFileUploadLinkRequest(const Account &account,
+                                                   const QString &repo_id,
+                                                   const QString &path,
+                                                   bool use_upload)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(
+              use_upload ? kGetFileUploadUrl : kGetFileUpdateUrl).arg(repo_id)),
+          SeafileApiRequest::METHOD_GET, account.token)
+{
+    setUrlParam("p", path);
+}
+
+void GetFileUploadLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+    QString reply_content(reply.readAll());
+
+    do {
+        if (reply_content.size() <= 2)
+            break;
+        reply_content.remove(0, 1);
+        reply_content.chop(1);
+        QUrl new_url(reply_content);
+
+        if (!new_url.isValid())
+            break;
+
+        emit success(reply_content);
+        return;
+    } while (0);
+    emit failed(ApiError::fromHttpError(500));
+}
+
+RenameDirentRequest::RenameDirentRequest(const Account &account,
+                                         const QString &repo_id,
+                                         const QString &path,
+                                         const QString &new_name,
+                                         bool is_file)
+    : SeafileApiRequest(
+        account.getAbsoluteUrl(
+            QString(is_file ? kGetFilesUrl: kGetDirentsUrl).arg(repo_id)),
+        SeafileApiRequest::METHOD_POST, account.token),
+    is_file_(is_file), repo_id_(repo_id), path_(path), new_name_(new_name)
+{
+    setUrlParam("p", path);
+
+    setFormParam("operation", "rename");
+    setFormParam("newname", new_name);
+}
+
+void RenameDirentRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success(repo_id_);
+}
+
+RemoveDirentRequest::RemoveDirentRequest(const Account &account,
+                                         const QString &repo_id,
+                                         const QString &path,
+                                         bool is_file)
+    : SeafileApiRequest(
+        account.getAbsoluteUrl(
+            QString(is_file ? kGetFilesUrl : kGetDirentsUrl).arg(repo_id)),
+        SeafileApiRequest::METHOD_DELETE, account.token),
+    is_file_(is_file), repo_id_(repo_id), path_(path)
+{
+    setUrlParam("p", path);
+}
+
+void RemoveDirentRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success(repo_id_);
+}
+
+RemoveDirentsRequest::RemoveDirentsRequest(const Account &account,
+                                           const QString &repo_id,
+                                           const QString &parent_path,
+                                           const QStringList& filenames)
+    : SeafileApiRequest(
+        account.getAbsoluteUrl(
+            QString(kRemoveDirentsURL).arg(repo_id)),
+        SeafileApiRequest::METHOD_POST, account.token),
+      repo_id_(repo_id), parent_path_(parent_path), filenames_(filenames)
+{
+    setUrlParam("p", parent_path_);
+    setFormParam("file_names", filenames_.join(":"));
+}
+
+void RemoveDirentsRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success(repo_id_);
+}
+
+MoveFileRequest::MoveFileRequest(const Account &account,
+                                 const QString &repo_id,
+                                 const QString &path,
+                                 const QString &dst_repo_id,
+                                 const QString &dst_dir_path)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kGetFilesUrl).arg(repo_id)),
+          SeafileApiRequest::METHOD_POST, account.token)
+{
+    setUrlParam("p", path);
+
+    setFormParam("operation", "move");
+    setFormParam("dst_repo", dst_repo_id);
+    setFormParam("dst_dir", dst_dir_path);
+}
+
+void MoveFileRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success();
+}
+
+CopyMultipleFilesRequest::CopyMultipleFilesRequest(const Account &account,
+                                                   const QString &repo_id,
+                                                   const QString &src_dir_path,
+                                                   const QStringList &src_file_names,
+                                                   const QString &dst_repo_id,
+                                                   const QString &dst_dir_path)
+    : SeafileApiRequest(
+        account.getAbsoluteUrl(QString(kFileOperationCopy).arg(repo_id)),
+    SeafileApiRequest::METHOD_POST, account.token),
+    repo_id_(repo_id),
+    src_dir_path_(src_dir_path),
+    src_file_names_(src_file_names),
+    dst_repo_id_(dst_repo_id)
+{
+    setUrlParam("p", src_dir_path);
+
+    setFormParam("file_names", src_file_names.join(":"));
+    setFormParam("dst_repo", dst_repo_id);
+    setFormParam("dst_dir", dst_dir_path);
+}
+
+void CopyMultipleFilesRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success(dst_repo_id_);
+}
+
+MoveMultipleFilesRequest::MoveMultipleFilesRequest(const Account &account,
+                                                   const QString &repo_id,
+                                                   const QString &src_dir_path,
+                                                   const QStringList &src_file_names,
+                                                   const QString &dst_repo_id,
+                                                   const QString &dst_dir_path)
+    : SeafileApiRequest(
+        account.getAbsoluteUrl(QString(kFileOperationMove).arg(repo_id)),
+    SeafileApiRequest::METHOD_POST, account.token),
+    repo_id_(repo_id),
+    src_dir_path_(src_dir_path),
+    src_file_names_(src_file_names),
+    dst_repo_id_(dst_repo_id)
+{
+    setUrlParam("p", src_dir_path);
+
+    setFormParam("file_names", src_file_names.join(":"));
+    setFormParam("dst_repo", dst_repo_id);
+    setFormParam("dst_dir", dst_dir_path);
+}
+
+void MoveMultipleFilesRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success(dst_repo_id_);
+}
+
+StarFileRequest::StarFileRequest(const Account &account,
+                                 const QString &repo_id,
+                                 const QString &path)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(kGetStarredFilesUrl),
+          SeafileApiRequest::METHOD_POST, account.token)
+{
+    setFormParam("repo_id", repo_id);
+    setFormParam("p", path);
+}
+
+void StarFileRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success();
+}
+
+UnstarFileRequest::UnstarFileRequest(const Account &account,
+                                     const QString &repo_id,
+                                     const QString &path)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(kGetStarredFilesUrl),
+          SeafileApiRequest::METHOD_DELETE, account.token)
+{
+    setUrlParam("repo_id", repo_id);
+    setUrlParam("p", path);
+}
+
+void UnstarFileRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success();
+}
+
+LockFileRequest::LockFileRequest(const Account &account, const QString &repo_id,
+                                 const QString &path, bool lock)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kGetFilesUrl).arg(repo_id)),
+          SeafileApiRequest::METHOD_PUT, account.token),
+      lock_(lock), repo_id_(repo_id), path_(path)
+{
+    setFormParam("p", path.startsWith("/") ? path : "/" + path);
+
+    setFormParam("operation", lock ? "lock" : "unlock");
+}
+
+void LockFileRequest::requestSuccess(QNetworkReply& reply)
+{
+    emit success(repo_id_);
+}
+
+GetFileUploadedBytesRequest::GetFileUploadedBytesRequest(
+    const Account &account,
+    const QString &repo_id,
+    const QString &parent_dir,
+    const QString &file_name)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kGetFileUploadedBytesUrl).arg(repo_id)),
+          SeafileApiRequest::METHOD_GET,
+          account.token),
+      repo_id_(repo_id),
+      parent_dir_(parent_dir),
+      file_name_(file_name)
+{
+    setUrlParam("parent_dir",
+                parent_dir.startsWith("/") ? parent_dir : "/" + parent_dir);
+    setUrlParam("file_name", file_name);
+}
+
+void GetFileUploadedBytesRequest::requestSuccess(QNetworkReply &reply)
+{
+    QString accept_ranges_header = reply.rawHeader("Accept-Ranges");
+    // printf ("accept_ranges_header = %s\n", toCStr(accept_ranges_header));
+    if (accept_ranges_header != "bytes") {
+        // Chunked uploading is not supported on the server
+        emit success(false, 0);
+        return;
+    }
+
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("GetFileUploadedBytesRequest: failed to parse json:%s\n",
+                 error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+    quint64 uploaded_bytes = dict["uploadedBytes"].toLongLong();
+    // printf ("uploadedBytes = %lld\n", uploaded_bytes);
+    emit success(true, uploaded_bytes);
+}
+
+GetIndexProgressRequest::GetIndexProgressRequest(const QUrl &url, const QString &task_id)
+    : SeafileApiRequest(url, SeafileApiRequest::METHOD_GET)
+{
+    setUrlParam("task_id", task_id);
+}
+
+void GetIndexProgressRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t *root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("GetIndexProgressRequest: failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+    QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+    ServerIndexProgress result;
+
+    result.total = dict.value("total").toInt();
+    result.indexed = dict.value("indexed").toInt();
+    result.status = dict.value("status").toInt();
+    emit success(result);
+}
+
+GetSmartLinkRequest::GetSmartLinkRequest(const Account& account,
+                                         const QString &repo_id,
+                                         const QString &path,
+                                         bool is_dir)
+    : SeafileApiRequest(
+          account.getAbsoluteUrl(QString(kGetSmartLink)),
+          SeafileApiRequest::METHOD_GET, account.token),
+      repo_id_(repo_id),
+      path_(path),
+      is_dir_(is_dir)
+{
+    setUrlParam("repo_id", repo_id);
+    setUrlParam("path", path);
+    setUrlParam("is_dir", is_dir ? "true" : "false");
+}
+
+void GetSmartLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+    json_error_t error;
+    json_t* root = parseJSON(reply, &error);
+    if (!root) {
+        qWarning("failed to parse json:%s\n", error.text);
+        emit failed(ApiError::fromJsonError());
+        return;
+    }
+
+    QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+    const char* smart_link =
+        json_string_value(json_object_get(json.data(), "smart_link"));
+
+    emit success(smart_link);
+}
+
diff --git a/src/filebrowser/file-browser-requests.h b/src/filebrowser/file-browser-requests.h
new file mode 100644 (file)
index 0000000..5ab5cb8
--- /dev/null
@@ -0,0 +1,392 @@
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_REQUESTS_H
+#define SEAFILE_CLIENT_FILE_BROWSER_REQUESTS_H
+
+#include <QList>
+#include <QStringList>
+
+#include "api/api-request.h"
+#include "seaf-dirent.h"
+
+class SeafDirent;
+class Account;
+class QDir;
+
+class GetDirentsRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    GetDirentsRequest(const Account& account,
+                      const QString& repo_id,
+                      const QString& path);
+
+    const QString& repoId() const { return repo_id_; }
+    const QString& path() const { return path_; }
+
+signals:
+    void success(bool current_readonly, const QList<SeafDirent> &dirents, const QString& repo_id);
+    void failed(const ApiError& error, const QString& repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetDirentsRequest)
+
+    const QString repo_id_;
+    const QString path_;
+    bool readonly_;
+};
+
+class GetFileDownloadLinkRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    GetFileDownloadLinkRequest(const Account &account,
+                               const QString &repo_id,
+                               const QString &path);
+
+    QString fileId() const { return file_id_; }
+signals:
+    void success(const QString& url);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetFileDownloadLinkRequest)
+
+    QString file_id_;
+};
+
+// TODO:
+// intergrate file creation into this class
+class CreateDirectoryRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    CreateDirectoryRequest(const Account &account, const QString &repo_id,
+                           const QString &path, bool create_parents = false);
+    const QString &repoId() { return repo_id_; }
+    const QString &path() { return path_; }
+
+signals:
+    void success(const QString& repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(CreateDirectoryRequest)
+    const QString repo_id_;
+    const QString path_;
+    bool create_parents_;
+};
+
+class RenameDirentRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    RenameDirentRequest(const Account &account, const QString &repo_id,
+                        const QString &path, const QString &new_path,
+                        bool is_file = true);
+
+    const bool& isFile() const { return is_file_; }
+    const QString& repoId() const { return repo_id_; }
+    const QString& path() const { return path_; }
+    const QString& newName() const { return new_name_; }
+
+signals:
+    void success(const QString& repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(RenameDirentRequest)
+
+    const bool is_file_;
+    const QString repo_id_;
+    const QString path_;
+    const QString new_name_;
+};
+
+class RemoveDirentRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    RemoveDirentRequest(const Account &account, const QString &repo_id,
+                        const QString &path, bool is_file = true);
+
+    const bool& isFile() const { return is_file_; }
+    const QString& repoId() const { return repo_id_; }
+    const QString& path() const { return path_; }
+
+signals:
+    void success(const QString& repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(RemoveDirentRequest)
+
+    const bool is_file_;
+    const QString repo_id_;
+    const QString path_;
+};
+
+class RemoveDirentsRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    RemoveDirentsRequest(const Account &account,
+                         const QString &repo_id,
+                         const QString &parent_path,
+                         const QStringList& filenames);
+
+    const QString& repoId() const { return repo_id_; }
+    const QString& parentPath() const { return parent_path_; }
+    const QStringList& filenames() const { return filenames_; }
+
+signals:
+    void success(const QString& repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(RemoveDirentsRequest)
+
+    const QString repo_id_;
+    const QString parent_path_;
+    const QStringList filenames_;
+};
+
+
+class GetSharedLinkRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    GetSharedLinkRequest(const Account &account, const QString &repo_id,
+                             const QString &path, bool is_file);
+
+signals:
+    void success(const QString& url, const QString& repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetSharedLinkRequest)
+    const QString repo_id_;
+};
+
+class GetFileUploadLinkRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    GetFileUploadLinkRequest(const Account &account,
+                             const QString &repo_id,
+                             const QString &path,
+                             bool use_upload = true);
+
+signals:
+    void success(const QString& url);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetFileUploadLinkRequest)
+};
+
+// Single File only
+class MoveFileRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    MoveFileRequest(const Account &account,
+                    const QString &repo_id,
+                    const QString &path,
+                    const QString &dst_repo_id,
+                    const QString &dst_dir_path);
+
+signals:
+    void success();
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(MoveFileRequest)
+};
+
+class CopyMultipleFilesRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    CopyMultipleFilesRequest(const Account &account,
+                             const QString &repo_id,
+                             const QString &src_dir_path,
+                             const QStringList &src_file_names,
+                             const QString &dst_repo_id,
+                             const QString &dst_dir_path);
+    const QString& repoId() { return repo_id_; }
+    const QString& srcPath() { return src_dir_path_; }
+    const QStringList& srcFileNames() { return src_file_names_; }
+
+signals:
+    void success(const QString& dst_repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(CopyMultipleFilesRequest)
+    const QString repo_id_;
+    const QString src_dir_path_;
+    const QStringList src_file_names_;
+    const QString dst_repo_id_;
+};
+
+class MoveMultipleFilesRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    MoveMultipleFilesRequest(const Account &account,
+                             const QString &repo_id,
+                             const QString &src_dir_path,
+                             const QStringList &src_file_names,
+                             const QString &dst_repo_id,
+                             const QString &dst_dir_path);
+    const QString& srcRepoId() { return repo_id_; }
+    const QString& srcPath() { return src_dir_path_; }
+    const QStringList& srcFileNames() { return src_file_names_; }
+
+signals:
+    void success(const QString& dst_repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(MoveMultipleFilesRequest)
+    const QString repo_id_;
+    const QString src_dir_path_;
+    const QStringList src_file_names_;
+    const QString dst_repo_id_;
+};
+
+class StarFileRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    StarFileRequest(const Account &account, const QString &repo_id,
+                    const QString &path);
+
+signals:
+    void success();
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(StarFileRequest)
+};
+
+class UnstarFileRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    UnstarFileRequest(const Account &account, const QString &repo_id,
+                      const QString &path);
+
+signals:
+    void success();
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(UnstarFileRequest)
+};
+
+class LockFileRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    LockFileRequest(const Account& account,
+                    const QString& repo_id,
+                    const QString& path,
+                    bool lock);
+
+    bool lock() const { return lock_; }
+    const QString & repoId() const { return repo_id_; }
+    const QString & path() const { return path_; }
+
+signals:
+    void success(const QString& repo_id);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(LockFileRequest);
+    const bool lock_;
+    const QString repo_id_;
+    const QString path_;
+};
+
+class GetFileUploadedBytesRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    GetFileUploadedBytesRequest(const Account& account,
+                                const QString& repo_id,
+                                const QString& parent_dir,
+                                const QString& file_name);
+
+    const QString & repoId() const { return repo_id_; }
+    const QString & parentDir() const { return parent_dir_; }
+    const QString & fileName() const { return file_name_; }
+
+signals:
+    void success(bool support_chunked_uploading, quint64 uploaded_bytes);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetFileUploadedBytesRequest);
+    const QString repo_id_;
+    const QString parent_dir_;
+    const QString file_name_;
+};
+
+struct ServerIndexProgress {
+    qint64 total;
+    qint64 indexed;
+    qint64 status;
+};
+
+class GetIndexProgressRequest : public SeafileApiRequest {
+    Q_OBJECT
+public:
+    GetIndexProgressRequest(const QUrl &url, const QString &task_id);
+signals:
+    void success(const ServerIndexProgress& result);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetIndexProgressRequest);
+};
+
+class GetSmartLinkRequest : public SeafileApiRequest
+{
+    Q_OBJECT
+public:
+    GetSmartLinkRequest(const Account& account,
+                        const QString& repo_id,
+                        const QString& path,
+                        bool is_dir);
+
+signals:
+    void success(const QString& smart_link);
+
+protected slots:
+    void requestSuccess(QNetworkReply& reply);
+
+private:
+    Q_DISABLE_COPY(GetSmartLinkRequest);
+    QString repo_id_;
+    QString path_;
+    bool is_dir_;
+};
+#endif  // SEAFILE_CLIENT_FILE_BROWSER_REQUESTS_H
diff --git a/src/filebrowser/file-browser-search-tab.cpp b/src/filebrowser/file-browser-search-tab.cpp
new file mode 100644 (file)
index 0000000..dc4f71c
--- /dev/null
@@ -0,0 +1,434 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "file-browser-dialog.h"
+#include "file-browser-search-tab.h"
+#include "ui/main-window.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/paint-utils.h"
+#include "seafile-applet.h"
+#include "api/requests.h"
+#include "repo-service.h"
+
+namespace {
+
+enum {
+    FILE_COLUMN_NAME = 0,
+    FILE_COLUMN_MTIME,
+    FILE_COLUMN_SIZE,
+    FILE_MAX_COLUMN
+};
+
+int kMarginLeft = 9;
+const int kDefaultColumnWidth = 120;
+const int kDefaultColumnHeight = 40;
+const int kColumnIconSize = 28;
+const int kFileNameColumnWidth = 200;
+const int kExtraPadding = 30;
+const int kDefaultColumnSum = kFileNameColumnWidth + kDefaultColumnWidth * 3 + kExtraPadding;
+const int kFileStatusIconSize = 16;
+const int kMarginBetweenFileNameAndStatusIcon = 5;
+
+const QColor kSelectedItemBackgroundcColor("#F9E0C7");
+const QColor kItemBackgroundColor("white");
+const QColor kItemBottomBorderColor("#ECECEC");
+const QColor kFileNameFontColor("black");
+const QColor kFontColor("#757575");
+
+} // anonymous namespace
+
+FileBrowserSearchItemDelegate::FileBrowserSearchItemDelegate(QObject *parent)
+    : QStyledItemDelegate(parent) {
+
+}
+
+void FileBrowserSearchItemDelegate::paint(QPainter *painter,
+                                     const QStyleOptionViewItem &option,
+                                     const QModelIndex &index) const {
+    const FileBrowserSearchModel *model = static_cast<const FileBrowserSearchModel*>(index.model());
+
+    // fix for the last item
+    QRect option_rect = option.rect;
+
+    // draw item's background
+    painter->save();
+    if (option.state & QStyle::State_Selected)
+        painter->fillRect(option_rect, kSelectedItemBackgroundcColor);
+    else
+        painter->fillRect(option_rect, kItemBackgroundColor);
+    painter->restore();
+
+    //
+    // draw item's border
+    //
+
+    // draw item's border for the first row only
+    static const QPen borderPen(kItemBottomBorderColor, 1);
+    if (index.row() == 0) {
+        painter->save();
+        painter->setPen(borderPen);
+        painter->drawLine(option_rect.topLeft(), option_rect.topRight());
+        painter->restore();
+    }
+    // draw item's border under the bottom
+    painter->save();
+    painter->setPen(borderPen);
+    painter->drawLine(option_rect.bottomLeft(), option_rect.bottomRight());
+    painter->restore();
+
+    QSize size = model->data(index, Qt::SizeHintRole).value<QSize>();
+    QString text = model->data(index, Qt::DisplayRole).value<QString>();
+    switch (index.column()) {
+    case FILE_COLUMN_NAME:
+    {
+        // draw icon
+        QPixmap pixmap = model->data(index, Qt::DecorationRole).value<QPixmap>();
+        double scale_factor = globalDevicePixelRatio();
+        // On Mac OSX (and other HDPI screens) the pixmap would be the 2x
+        // version (but the draw rect area is still the same size), so when
+        // computing the offsets we need to divide it by the scale factor.
+        int icon_width = qMin(kColumnIconSize,
+                             int((double)pixmap.width() / (double)scale_factor));
+        int icon_height = qMin(size.height(),
+                               int((double)pixmap.height() / (double)scale_factor));
+        int alignX = (kColumnIconSize - icon_width) / 2;
+        int alignY = (size.height() - icon_height) / 2;
+
+#ifdef Q_OS_WIN32
+    kMarginLeft = 4;
+#endif
+
+        QRect icon_bound_rect(
+            option_rect.topLeft() + QPoint(kMarginLeft + alignX, alignY - 2),
+            QSize(icon_width, icon_height));
+
+        painter->save();
+        painter->drawPixmap(icon_bound_rect, pixmap);
+        painter->restore();
+
+        // draw text
+        QFont font = model->data(index, Qt::FontRole).value<QFont>();
+        QRect rect(option_rect.topLeft() + QPoint(kMarginLeft + 2 * 2 + kColumnIconSize, -2),
+                   size - QSize(kColumnIconSize + kMarginLeft, 0));
+        painter->setPen(kFileNameFontColor);
+        painter->setFont(font);
+        painter->drawText(
+            rect,
+            Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
+            fitTextToWidth(
+                text,
+                option.font,
+                rect.width() - kMarginBetweenFileNameAndStatusIcon - kFileStatusIconSize - 5));
+
+    }
+         break;
+
+    case FILE_COLUMN_SIZE:
+        if (!text.isEmpty())
+            text = ::readableFileSize(model->data(index, Qt::DisplayRole).value<quint64>());
+    case FILE_COLUMN_MTIME:
+    {
+        if (index.column() == FILE_COLUMN_MTIME) {
+            text = ::translateCommitTime(model->data(index, Qt::DisplayRole).value<quint64>(), true);
+        }
+        QFont font = model->data(index, Qt::FontRole).value<QFont>();
+        QRect rect(option_rect.topLeft() + QPoint(9, -2), size - QSize(10, 0));
+        painter->save();
+        painter->setPen(kFontColor);
+        painter->setFont(font);
+        painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, text);
+        painter->restore();
+    }
+        break;
+    default:
+        qWarning() << "invalid item (row)";
+        break;
+    }
+}
+
+FileBrowserSearchView::FileBrowserSearchView(QWidget* parent)
+    : QTableView(parent),
+      parent_(qobject_cast<FileBrowserDialog*>(parent)),
+      search_model_(NULL),
+      proxy_model_(NULL)
+{
+    verticalHeader()->hide();
+    verticalHeader()->setDefaultSectionSize(kDefaultColumnHeight);
+    horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
+    horizontalHeader()->setStretchLastSection(true);
+    horizontalHeader()->setCascadingSectionResizes(true);
+    horizontalHeader()->setHighlightSections(false);
+    horizontalHeader()->setSortIndicatorShown(true);
+    horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+
+    setGridStyle(Qt::NoPen);
+    setShowGrid(false);
+    setContentsMargins(0, 0, 0, 0);
+    setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+
+    setSelectionBehavior(QAbstractItemView::SelectRows);
+    setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+    setMouseTracking(true);
+    setDragDropMode(QAbstractItemView::DropOnly);
+
+    connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+                this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+
+    setupContextMenu();
+}
+
+void FileBrowserSearchView::setupContextMenu()
+{
+    context_menu_ = new QMenu(this);
+    connect(parent_, SIGNAL(aboutToClose()),
+            context_menu_, SLOT(close()));
+    open_parent_dir_action_ = new QAction(tr("&Show in folder"), this);
+    open_parent_dir_action_->setIcon(QIcon(":/images/toolbar/file-gray.png"));
+    open_parent_dir_action_->setIconVisibleInMenu(true);
+    open_parent_dir_action_->setStatusTip(tr("Show in folder"));
+    connect(open_parent_dir_action_, SIGNAL(triggered()),
+            this, SLOT(openParentDir()));
+    context_menu_->addAction(open_parent_dir_action_);
+    this->addAction(open_parent_dir_action_);
+}
+
+void FileBrowserSearchView::contextMenuEvent(QContextMenuEvent *event)
+{
+    QPoint position = event->pos();
+    const QModelIndex proxy_index = indexAt(position);
+    position = viewport()->mapToGlobal(position);
+    if (!proxy_index.isValid()) {
+        return;
+    }
+
+    const QModelIndex index = proxy_model_->mapToSource(proxy_index);
+    const int row = index.row();
+    const FileSearchResult *result = search_model_->resultAt(row);
+    if (!result)
+        return;
+
+    QItemSelectionModel *selections = this->selectionModel();
+    QModelIndexList selected = selections->selectedRows();
+    if (selected.size() == 1) {
+        open_parent_dir_action_->setEnabled(true);
+        search_item_.reset(new FileSearchResult(*result));
+    } else {
+        open_parent_dir_action_->setEnabled(false);
+        return;
+    }
+
+    context_menu_->exec(position); // synchronously
+    search_item_.reset(NULL);
+}
+
+void FileBrowserSearchView::openParentDir()
+{
+    parent_->enterPath(::getParentPath(search_item_->fullpath));
+    emit clearSearchBar();
+}
+
+void FileBrowserSearchView::onItemDoubleClicked(const QModelIndex& index)
+{
+    const FileSearchResult *result =
+            search_model_->resultAt(proxy_model_->mapToSource(index).row());
+    if (result->name.isEmpty() || result->fullpath.isEmpty())
+        return;
+
+    if (result->fullpath.endsWith("/"))
+        emit clearSearchBar();
+
+    RepoService::instance()->openLocalFile(result->repo_id, result->fullpath);
+}
+
+void FileBrowserSearchView::setModel(QAbstractItemModel *model)
+{
+    search_model_ = qobject_cast<FileBrowserSearchModel*>(model);
+    if (!search_model_)
+        return;
+    proxy_model_ = new FileSearchSortFilterProxyModel(search_model_);
+    proxy_model_->setSourceModel(search_model_);
+    QTableView::setModel(proxy_model_);
+
+//    setColumnHidden(FILE_COLUMN_PROGRESS, true);
+    connect(model, SIGNAL(modelAboutToBeReset()), this, SLOT(onAboutToReset()));
+    setSortingEnabled(true);
+
+    // set default sort by folder
+    sortByColumn(FILE_COLUMN_NAME, Qt::AscendingOrder);
+}
+
+void FileBrowserSearchView::onAboutToReset()
+{
+    search_item_.reset(NULL);
+}
+
+void FileBrowserSearchView::resizeEvent(QResizeEvent *event)
+{
+    QTableView::resizeEvent(event);
+    if (search_model_)
+        search_model_->onResize(event->size());
+}
+
+FileBrowserSearchModel::FileBrowserSearchModel(QObject *parent)
+    : QAbstractTableModel(parent),
+      name_column_width_(kFileNameColumnWidth)
+{
+
+}
+
+void FileBrowserSearchModel::setSearchResult(const std::vector<FileSearchResult>& results)
+{
+    beginResetModel();
+    results_ = results;
+    endResetModel();
+}
+
+int FileBrowserSearchModel::rowCount(const QModelIndex &parent) const
+{
+    return results_.size();
+}
+
+int FileBrowserSearchModel::columnCount(const QModelIndex &index) const
+{
+    return FILE_MAX_COLUMN;
+}
+
+QVariant FileBrowserSearchModel::data(const QModelIndex &index, int role) const
+{
+    if (!index.isValid() || index.row() >= (int)results_.size()) {
+        return QVariant();
+    }
+    const int column = index.column();
+    const int row = index.row();
+    const FileSearchResult& result = results_[row];
+
+    if (role == Qt::DecorationRole && column == FILE_COLUMN_NAME) {
+        QIcon icon;
+
+        if (result.fullpath.endsWith("/")) {
+            icon = QIcon(":/images/files_v2/file_folder.png");
+        } else {
+            icon = QIcon(getIconByFileNameV2(result.name));
+        }
+
+        return icon.pixmap(kColumnIconSize, kColumnIconSize);
+    }
+
+    if (role == Qt::SizeHintRole) {
+        QSize qsize(kDefaultColumnWidth, kDefaultColumnHeight);
+        switch (column) {
+        case FILE_COLUMN_NAME:
+            qsize.setWidth(name_column_width_);
+            break;
+        case FILE_COLUMN_SIZE:
+        case FILE_COLUMN_MTIME:
+            qsize.setWidth(name_column_width_);
+        default:
+            break;
+        }
+        return qsize;
+    }
+
+    //DisplayRole
+    switch (column) {
+    case FILE_COLUMN_NAME:
+
+        return result.name;
+    case FILE_COLUMN_SIZE:
+        if (result.fullpath.endsWith("/"))
+            return "";
+        return result.size;
+    case FILE_COLUMN_MTIME:
+        return result.last_modified;
+    default:
+        return QVariant();
+    }
+}
+
+QVariant FileBrowserSearchModel::headerData(int section,
+                                            Qt::Orientation orientation,
+                                            int role) const
+{
+    if (orientation == Qt::Vertical) {
+        return QVariant();
+    }
+
+    if (role == Qt::TextAlignmentRole) {
+        return Qt::AlignLeft + Qt::AlignVCenter;
+    }
+
+    if (role == Qt::DisplayRole) {
+        switch (section) {
+        case FILE_COLUMN_NAME:
+            return tr("Name");
+        case FILE_COLUMN_SIZE:
+            return tr("Size");
+        case FILE_COLUMN_MTIME:
+            return tr("Last Modified");
+        default:
+            return QVariant();
+        }
+    }
+
+    if (role == Qt::FontRole) {
+        QFont font;
+        font.setPixelSize(12);
+        return font;
+    }
+
+    if (role == Qt::ForegroundRole) {
+        return QBrush(kFontColor);
+    }
+
+    if (role == Qt::SizeHintRole && section == FILE_COLUMN_NAME) {
+        if (results_.empty()) {
+            return QSize(name_column_width_, 0);
+        }
+    }
+    return QVariant();
+}
+
+void FileBrowserSearchModel::onResize(const QSize &size)
+{
+    name_column_width_ = size.width() - kDefaultColumnSum + kFileNameColumnWidth;
+    // name_column_width_ should be always larger than kFileNameColumnWidth
+    if (results_.empty())
+        return;
+    emit dataChanged(index(0, FILE_COLUMN_NAME),
+                     index(results_.size()-1 , FILE_COLUMN_NAME));
+}
+
+const FileSearchResult* FileBrowserSearchModel::resultAt(int row) const
+{
+    int nSize = static_cast<int>(results_.size());
+    if (row >= nSize)
+        return NULL;
+
+    return &results_[row];
+}
+
+bool FileSearchSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
+{
+    bool is_dir_left = search_model_->resultAt(left.row())->fullpath.endsWith("/");
+    bool is_dir_right = search_model_->resultAt(right.row())->fullpath.endsWith("/");
+    if (is_dir_left != is_dir_right) {
+        return sortOrder() != Qt::AscendingOrder ? is_dir_right
+                                                 : !is_dir_right;
+    }
+    else if ((left.column() == FILE_COLUMN_NAME) &&
+             (right.column() == FILE_COLUMN_NAME)) {
+        const QString left_name = search_model_->resultAt(left.row())->name;
+        const QString right_name = search_model_->resultAt(right.row())->name;
+        return digitalCompare(left_name, right_name) < 0;
+    }
+    else {
+        return QSortFilterProxyModel::lessThan(left, right);
+    }
+}
diff --git a/src/filebrowser/file-browser-search-tab.h b/src/filebrowser/file-browser-search-tab.h
new file mode 100644 (file)
index 0000000..eef1e22
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef FILE_BROWSER_UI_SEARCH_TAB_H
+#define FILE_BROWSER_UI_SEARCH_TAB_H
+
+#include <vector>
+#include <QTableView>
+#include <QStandardItem>
+#include <QAbstractTableModel>
+#include <QStyledItemDelegate>
+#include <QSortFilterProxyModel>
+
+#include "api/requests.h"
+
+class QAction;
+class QMenu;
+
+class FileBrowserSearchItemDelegate : public QStyledItemDelegate {
+    Q_OBJECT
+public:
+    FileBrowserSearchItemDelegate(QObject *parent);
+    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+};
+
+class FileBrowserDialog;
+class FileBrowserSearchModel;
+
+class FileBrowserSearchView : public QTableView {
+    Q_OBJECT
+public:
+    FileBrowserSearchView(QWidget *parent);
+    void setModel(QAbstractItemModel *model);
+
+    void resizeEvent(QResizeEvent *event);
+    void setupContextMenu();
+signals:
+    void clearSearchBar();
+private slots:
+    void onAboutToReset();
+    void openParentDir();
+    void onItemDoubleClicked(const QModelIndex& index);
+private:
+
+    Q_DISABLE_COPY(FileBrowserSearchView)
+
+    void contextMenuEvent(QContextMenuEvent *event);
+
+    FileBrowserDialog *parent_;
+    FileBrowserSearchModel *search_model_;
+    QSortFilterProxyModel *proxy_model_;
+
+    QScopedPointer<const FileSearchResult> search_item_;
+    QMenu *context_menu_;
+    QAction *open_parent_dir_action_;
+};
+
+
+class FileBrowserSearchModel : public QAbstractTableModel {
+    Q_OBJECT
+public:
+    FileBrowserSearchModel(QObject *parent=0);
+
+    int rowCount(const QModelIndex &parent=QModelIndex()) const;
+    int columnCount(const QModelIndex &index) const;
+
+    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+    void setSearchResult(const std::vector<FileSearchResult>& results);
+
+    void onResize(const QSize &size);
+
+    const FileSearchResult* resultAt(int row) const;
+
+private:
+    Q_DISABLE_COPY(FileBrowserSearchModel)
+
+    std::vector<FileSearchResult> results_;
+
+    int name_column_width_;
+};
+
+class FileSearchSortFilterProxyModel : public QSortFilterProxyModel {
+    Q_OBJECT
+public:
+    FileSearchSortFilterProxyModel(FileBrowserSearchModel *parent)
+        : QSortFilterProxyModel(parent), search_model_(parent) {
+        setSortCaseSensitivity(Qt::CaseInsensitive);
+    }
+    bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
+
+private:
+    FileBrowserSearchModel* search_model_;
+};
+
+
+#endif // FILE_BROWSER_UI_SEARCH_TAB_H
diff --git a/src/filebrowser/file-table.cpp b/src/filebrowser/file-table.cpp
new file mode 100644 (file)
index 0000000..4382111
--- /dev/null
@@ -0,0 +1,1225 @@
+#include <QtGlobal>
+#include <QtWidgets>
+#include <QTimer>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/paint-utils.h"
+#include "seaf-dirent.h"
+#include "utils/utils-mac.h"
+#include "seafile-applet.h"
+
+#include "file-browser-dialog.h"
+#include "data-mgr.h"
+#include "transfer-mgr.h"
+#include "tasks.h"
+
+#include "file-table.h"
+
+namespace {
+
+enum {
+    FILE_COLUMN_NAME = 0,
+    FILE_COLUMN_MTIME,
+    FILE_COLUMN_SIZE,
+    FILE_COLUMN_MODIFIER,
+    FILE_COLUMN_PROGRESS,
+    FILE_MAX_COLUMN
+};
+
+int kMarginLeft = 9;
+const int kDefaultColumnWidth = 120;
+const int kDefaultColumnHeight = 40;
+const int kColumnIconSize = 28;
+const int kFileNameColumnWidth = 200;
+const int kExtraPadding = 30;
+const int kDefaultColumnSum = kFileNameColumnWidth + kDefaultColumnWidth * 3 + kExtraPadding;
+const int kLockIconSize = 16;
+const int kFileStatusIconSize = 16;
+const int kMarginBetweenFileNameAndStatusIcon = 5;
+
+const int kRefreshProgressInterval = 1000;
+
+const QColor kSelectedItemBackgroundcColor("#F9E0C7");
+const QColor kItemBackgroundColor("white");
+const QColor kItemBottomBorderColor("#ECECEC");
+const QColor kFileNameFontColor("black");
+const QColor kFontColor("#757575");
+const QString kProgressBarStyle("QProgressBar "
+        "{ border: 1px solid grey; border-radius: 2px; } "
+        "QProgressBar::chunk { background-color: #f0f0f0; width: 1px; }");
+
+enum {
+    NOT_LOCKED = 0,
+    LOCKED_BY_ME,
+    LOCKED_BY_OTHERS
+};
+
+const int DirentLockStatusRole = Qt::UserRole + 1;
+const int DirentLockOwnerRole = Qt::UserRole + 2;
+const int DirentCacheStatusRole = Qt::UserRole + 3;
+
+QIcon getFileStatusIcon(AutoUpdateManager::FileStatus file_status)
+{
+    QString icon;
+    const QString prefix = ":/images/sync/";
+    switch (file_status) {
+        case AutoUpdateManager::SYNCED:
+            icon = "status-done";
+            break;
+        case AutoUpdateManager::UPLOADING:
+            icon = "status-syncing";
+            break;
+        case AutoUpdateManager::NOT_SYNCED:
+            icon = "exclamation";
+            break;
+    }
+
+    return QIcon(prefix + icon + ".png");
+}
+
+} // namespace
+
+FileTableViewDelegate::FileTableViewDelegate(QObject *parent)
+  : QStyledItemDelegate(parent) {
+}
+
+void FileTableViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+    const FileTableModel *model = static_cast<const FileTableModel*>(index.model());
+
+    // fix for the last item
+    QRect option_rect = option.rect;
+
+    // draw item's background
+    painter->save();
+    if (option.state & QStyle::State_Selected)
+        painter->fillRect(option_rect, kSelectedItemBackgroundcColor);
+    else
+        painter->fillRect(option_rect, kItemBackgroundColor);
+    painter->restore();
+
+    //
+    // draw item's border
+    //
+
+    // draw item's border for the first row only
+    static const QPen borderPen(kItemBottomBorderColor, 1);
+    if (index.row() == 0) {
+        painter->save();
+        painter->setPen(borderPen);
+        painter->drawLine(option_rect.topLeft(), option_rect.topRight());
+        painter->restore();
+    }
+    // draw item's border under the bottom
+    painter->save();
+    painter->setPen(borderPen);
+    painter->drawLine(option_rect.bottomLeft(), option_rect.bottomRight());
+    painter->restore();
+
+    //
+    // draw item
+    //
+
+    QSize size = model->data(index, Qt::SizeHintRole).value<QSize>();
+    QString text = model->data(index, Qt::DisplayRole).value<QString>();
+    switch (index.column()) {
+    case FILE_COLUMN_NAME:
+    {
+        // draw icon
+        QPixmap pixmap = model->data(index, Qt::DecorationRole).value<QPixmap>();
+        double scale_factor = globalDevicePixelRatio();
+        // On Mac OSX (and other HDPI screens) the pixmap would be the 2x
+        // version (but the draw rect area is still the same size), so when
+        // computing the offsets we need to divide it by the scale factor.
+        int icon_width = qMin(kColumnIconSize,
+                             int((double)pixmap.width() / (double)scale_factor));
+        int icon_height = qMin(size.height(),
+                               int((double)pixmap.height() / (double)scale_factor));
+        int alignX = (kColumnIconSize - icon_width) / 2;
+        int alignY = (size.height() - icon_height) / 2;
+
+#ifdef Q_OS_WIN32
+    kMarginLeft = 4;
+#endif
+
+        QRect icon_bound_rect(
+            option_rect.topLeft() + QPoint(kMarginLeft + alignX, alignY - 2),
+            QSize(icon_width, icon_height));
+
+        painter->save();
+        painter->drawPixmap(icon_bound_rect, pixmap);
+        painter->restore();
+
+        int lock_status = model->data(index, DirentLockStatusRole).toInt();
+        if (lock_status != NOT_LOCKED) {
+            painter->save();
+            QString image = QString(":/images/filebrowser/%1.png").arg(
+                lock_status == LOCKED_BY_ME ? "locked-by-me" : "locked");
+            QPixmap locked_pixmap = QIcon(image).pixmap(kLockIconSize, kLockIconSize);
+            int alignX = (kColumnIconSize / 2) + 3;
+            int alignY = (kColumnIconSize / 2) + 2;
+            painter->drawPixmap(option_rect.topLeft() + QPoint(kMarginLeft + alignX, alignY), locked_pixmap);
+            painter->restore();
+        }
+
+        // draw text
+        QFont font = model->data(index, Qt::FontRole).value<QFont>();
+        QRect rect(option_rect.topLeft() + QPoint(kMarginLeft + 2 * 2 + kColumnIconSize, -2),
+                   size - QSize(kColumnIconSize + kMarginLeft, 0));
+        painter->setPen(kFileNameFontColor);
+        painter->setFont(font);
+        painter->drawText(
+            rect,
+            Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
+            fitTextToWidth(
+                text,
+                option.font,
+                rect.width() - kMarginBetweenFileNameAndStatusIcon - kFileStatusIconSize - 5));
+
+        QVariant file_status_v = model->data(index, DirentCacheStatusRole);
+        if (!file_status_v.isNull()) {
+            AutoUpdateManager::FileStatus file_status = (AutoUpdateManager::FileStatus)file_status_v.toInt();
+            // printf ("file status is %d\n", (int)file_status);
+
+            QPoint status_icon_pos = option.rect.topRight() - QPoint(kFileStatusIconSize + 3, 0);
+            status_icon_pos.setY(option.rect.center().y() - (kFileStatusIconSize / 2));
+            QRect status_icon_rect(status_icon_pos, QSize(kFileStatusIconSize, kFileStatusIconSize));
+
+            QPixmap status_icon_pixmap = getFileStatusIcon(file_status).pixmap(status_icon_rect.size());
+            qDebug("file browser icon status is %d\n", (int)file_status);
+
+            painter->save();
+            painter->drawPixmap(status_icon_rect, status_icon_pixmap);
+            painter->restore();
+        }
+    }
+    break;
+    case FILE_COLUMN_SIZE:
+    {
+        // if we has progress, draw the progress bar
+        QString text_progress = model->data(model->index(index.row(), FILE_COLUMN_PROGRESS), Qt::DisplayRole).value<QString>();
+        if (!text_progress.isEmpty()) {
+            // get the progress value from the Model
+            if (text_progress.endsWith('%'))
+                text_progress.resize(text_progress.size() - 1);
+            const int progress = text_progress.toInt();
+
+            // Customize style using style-sheet..
+            QProgressBar progressBar;
+            progressBar.resize(QSize(size.width() - 155, size.height() / 2 - 4));
+            progressBar.setMinimum(0);
+            progressBar.setMaximum(100);
+            progressBar.setValue(progress);
+            progressBar.setAlignment(Qt::AlignCenter);
+            progressBar.setStyleSheet(kProgressBarStyle);
+            painter->save();
+            painter->translate(option_rect.topLeft() + QPoint(0, size.height() / 4 - 1));
+            progressBar.render(painter);
+            painter->restore();
+            break;
+        }
+        // else, draw the text only
+    }
+    // FILE_COLUMN_SIZE comes here
+        if (!text.isEmpty())
+            text = ::readableFileSize(model->data(index, Qt::DisplayRole).value<quint64>());
+    // no break, continue
+    case FILE_COLUMN_MTIME:
+        if (index.column() == FILE_COLUMN_MTIME)
+            text = ::translateCommitTime(model->data(index, Qt::DisplayRole).value<quint64>(), true);
+    // no break, continue
+    case FILE_COLUMN_MODIFIER:
+    {
+        if (index.column() == FILE_COLUMN_MODIFIER) {
+            text = model->data(index, Qt::DisplayRole).toString();
+        }
+        QFont font = model->data(index, Qt::FontRole).value<QFont>();
+        QRect rect(option_rect.topLeft() + QPoint(9, -2), size - QSize(10, 0));
+        painter->save();
+        painter->setPen(kFontColor);
+        painter->setFont(font);
+        painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, text);
+        painter->restore();
+    }
+    break;
+    case FILE_COLUMN_PROGRESS:
+    // don't do anything
+    break;
+    default:
+    // never reached here
+    // QStyledItemDelegate::paint(painter, option, index);
+    qWarning() << "invalid item (row)";
+    break;
+    }
+}
+
+FileTableView::FileTableView(QWidget *parent)
+    : QTableView(parent),
+      parent_(qobject_cast<FileBrowserDialog*>(parent)),
+      source_model_(NULL),
+      proxy_model_(NULL)
+{
+    verticalHeader()->hide();
+    verticalHeader()->setDefaultSectionSize(kDefaultColumnHeight);
+    horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
+    horizontalHeader()->setStretchLastSection(true);
+    horizontalHeader()->setCascadingSectionResizes(true);
+    horizontalHeader()->setHighlightSections(false);
+    horizontalHeader()->setSortIndicatorShown(true);
+    horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+
+    setGridStyle(Qt::NoPen);
+    setShowGrid(false);
+    setContentsMargins(0, 0, 0, 0);
+    setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+
+    setSelectionBehavior(QAbstractItemView::SelectRows);
+    setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+    setMouseTracking(true);
+    setDragDropMode(QAbstractItemView::DropOnly);
+    setItemDelegate(new FileTableViewDelegate(this));
+
+    connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+            this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+
+    setupContextMenu();
+}
+
+void FileTableView::setModel(QAbstractItemModel *model)
+{
+    source_model_ = qobject_cast<FileTableModel*>(model);
+    if (!source_model_)
+        return;
+    proxy_model_ = new FileTableSortFilterProxyModel(source_model_);
+    proxy_model_->setSourceModel(source_model_);
+    QTableView::setModel(proxy_model_);
+
+    setColumnHidden(FILE_COLUMN_PROGRESS, true);
+    connect(model, SIGNAL(modelAboutToBeReset()), this, SLOT(onAboutToReset()));
+    setSortingEnabled(true);
+
+    // set default sort by folder
+    sortByColumn(FILE_COLUMN_NAME, Qt::AscendingOrder);
+}
+
+const SeafDirent *FileTableView::getSelectedItemFromSource()
+{
+    QItemSelectionModel *selections = this->selectionModel();
+    QModelIndexList selected = selections->selectedRows();
+    if (selected.size() == 1)
+        return source_model_->direntAt(proxy_model_->mapToSource(selected.front()).row());
+    return NULL;
+}
+
+QList<const SeafDirent *> FileTableView::getSelectedItemsFromSource()
+{
+    QList<const SeafDirent *> results;
+    QItemSelectionModel *selections = this->selectionModel();
+    QModelIndexList selected = selections->selectedRows();
+    results.reserve(selected.size());
+    for (int i = 0; i != selected.size() ; i++) {
+        results.push_back(source_model_->direntAt(proxy_model_->mapToSource(selected[i]).row()));
+    }
+    return results;
+}
+
+void FileTableView::setupContextMenu()
+{
+    context_menu_ = new QMenu(this);
+    connect(parent_, SIGNAL(aboutToClose()),
+            context_menu_, SLOT(close()));
+
+    retry_upload_cached_file_action_ = new QAction(tr("Retry Upload"), this);
+    connect(retry_upload_cached_file_action_, SIGNAL(triggered()),
+            this, SLOT(onRetryUploadCachedFile()));
+    delete_local_version_action_ = new QAction(tr("Delete Local Version"), this);
+    connect(delete_local_version_action_, SIGNAL(triggered()),
+            this, SLOT(onDeleteLocalVersion()));
+    local_version_saveas_action_ = new QAction(tr("Local Version Save As..."), this);
+    connect(local_version_saveas_action_, SIGNAL(triggered()),
+            this, SLOT(onLocalVersionSaveAs()));
+    saveas_action_ = new QAction(tr("&Save As..."), this);
+    connect(saveas_action_, SIGNAL(triggered()),
+            this, SLOT(onSaveAs()));
+    saveas_action_->setShortcut(Qt::ALT + Qt::Key_S);
+
+    lock_action_ = new QAction(tr("&Lock"), this);
+    connect(lock_action_, SIGNAL(triggered()), this, SLOT(onLock()));
+    lock_action_->setShortcut(Qt::ALT + Qt::Key_L);
+    if (!parent_->account_.isAtLeastProVersion(4, 2, 0)) {
+        lock_action_->setEnabled(false);
+        lock_action_->setToolTip(tr("This feature is available in pro version only\n"));
+    }
+
+    rename_action_ = new QAction(tr("&Rename"), this);
+    connect(rename_action_, SIGNAL(triggered()),
+            this, SLOT(onRename()));
+    rename_action_->setShortcut(Qt::ALT + Qt::Key_R);
+
+    remove_action_ = new QAction(tr("&Delete"), this);
+    connect(remove_action_, SIGNAL(triggered()),
+            this, SLOT(onRemove()));
+    // remove_action_->setShortcut(QKeySequence::Delete);
+
+    share_action_ = new QAction(tr("&Generate %1 Download Link").arg(getBrand()), this);
+    connect(share_action_, SIGNAL(triggered()),
+            this, SLOT(onShare()));
+    share_action_->setShortcut(Qt::ALT + Qt::Key_G);
+
+    share_to_user_action_ = new QAction(tr("Share to User"), this);
+    connect(share_to_user_action_, SIGNAL(triggered()),
+            this, SLOT(onShareToUser()));
+
+    share_to_group_action_ = new QAction(tr("Share to Group"), this);
+    connect(share_to_group_action_, SIGNAL(triggered()),
+            this, SLOT(onShareToGroup()));
+
+    share_seafile_action_ = new QAction(tr("G&enerate %1 Internal Link").arg(getBrand()), this);
+    connect(share_seafile_action_, SIGNAL(triggered()),
+            this, SLOT(onShareSeafile()));
+    share_seafile_action_->setShortcut(Qt::ALT + Qt::Key_E);
+
+    if (parent_->repo_.encrypted) {
+        share_action_->setEnabled(false);
+        share_to_user_action_->setEnabled(false);
+        share_to_group_action_->setEnabled(false);
+    }
+
+    update_action_ = new QAction(tr("&Update"), this);
+    connect(update_action_, SIGNAL(triggered()), this, SLOT(onUpdate()));
+    update_action_->setShortcut(Qt::ALT + Qt::Key_U);
+
+    copy_action_ = new QAction(tr("&Copy"), this);
+    connect(copy_action_, SIGNAL(triggered()), this, SLOT(onCopy()));
+    copy_action_->setShortcut(QKeySequence::Copy);
+
+    move_action_ = new QAction(tr("Cu&t"), this);
+    connect(move_action_, SIGNAL(triggered()), this, SLOT(onMove()));
+    move_action_->setShortcut(QKeySequence::Cut);
+
+    paste_action_ = new QAction(tr("&Paste"), this);
+    connect(paste_action_, SIGNAL(triggered()), this, SIGNAL(direntPaste()));
+    paste_action_->setShortcut(QKeySequence::Paste);
+
+    if (parent_->current_readonly_) {
+        move_action_->setEnabled(false);
+        paste_action_->setEnabled(false);
+    }
+
+    cancel_download_action_ = new QAction(tr("Canc&el Download"), this);
+    connect(cancel_download_action_, SIGNAL(triggered()),
+            this, SLOT(onCancelDownload()));
+    cancel_download_action_->setShortcut(Qt::ALT + Qt::Key_C);
+
+    sync_subdirectory_action_ = new QAction(tr("&Sync this folder"), this);
+    connect(sync_subdirectory_action_, SIGNAL(triggered()),
+            this, SLOT(onSyncSubdirectory()));
+    // sync_subdirectory_action_->setShortcut(Qt::ALT + Qt::Key_S);
+    if (!parent_->account_.isAtLeastVersion(4, 1, 0)) {
+        sync_subdirectory_action_->setEnabled(false);
+        sync_subdirectory_action_->setToolTip(tr("This feature is available in pro version only\n"));
+    }
+
+    open_local_cache_folder_action_ = new QAction(tr("Open Local Cache Folder"), this);
+    connect(open_local_cache_folder_action_, SIGNAL(triggered()),
+                this, SLOT(onOpenLocalCacheFolder()));
+
+    context_menu_->addAction(retry_upload_cached_file_action_);
+    context_menu_->addAction(delete_local_version_action_);
+    context_menu_->addAction(local_version_saveas_action_);
+    context_menu_->addSeparator();
+    context_menu_->addAction(saveas_action_);
+    context_menu_->addAction(share_action_);
+    context_menu_->addAction(share_seafile_action_);
+    context_menu_->addAction(share_to_user_action_);
+    context_menu_->addAction(share_to_group_action_);
+    context_menu_->addSeparator();
+    context_menu_->addAction(move_action_);
+    context_menu_->addAction(copy_action_);
+    context_menu_->addAction(paste_action_);
+    context_menu_->addSeparator();
+    context_menu_->addAction(lock_action_);
+    context_menu_->addAction(rename_action_);
+    context_menu_->addAction(remove_action_);
+    context_menu_->addSeparator();
+    // context_menu_->addAction(update_action_);
+    context_menu_->addAction(cancel_download_action_);
+    context_menu_->addAction(sync_subdirectory_action_);
+    context_menu_->addSeparator();
+    context_menu_->addAction(open_local_cache_folder_action_);
+
+    this->addAction(retry_upload_cached_file_action_);
+    this->addAction(delete_local_version_action_);
+    this->addAction(local_version_saveas_action_);
+    this->addAction(saveas_action_);
+    this->addAction(share_action_);
+    this->addAction(share_seafile_action_);
+    this->addAction(move_action_);
+    this->addAction(copy_action_);
+    this->addAction(paste_action_);
+    this->addAction(lock_action_);
+    this->addAction(rename_action_);
+    this->addAction(remove_action_);
+    // this->addAction(update_action_);
+    this->addAction(cancel_download_action_);
+    this->addAction(sync_subdirectory_action_);
+    this->addAction(open_local_cache_folder_action_);
+
+    paste_only_menu_ = new QMenu(this);
+    paste_only_menu_->addAction(paste_action_);
+}
+
+void FileTableView::contextMenuEvent(QContextMenuEvent *event)
+{
+    QPoint position = event->pos();
+    const QModelIndex proxy_index = indexAt(position);
+    position = viewport()->mapToGlobal(position);
+
+    retry_upload_cached_file_action_->setVisible(false);
+    delete_local_version_action_->setVisible(false);
+    local_version_saveas_action_->setVisible(false);
+    open_local_cache_folder_action_->setEnabled(false);
+
+    //
+    // paste_action shows only if there are files in the clipboard
+    // and is enabled only if it comes from the same account
+    //
+    paste_action_->setVisible(parent_->hasFilesToBePasted());
+
+    //
+    // show paste only menu for no items
+    // paste-dedicated menu
+    //
+    paste_action_->setEnabled(!parent_->current_readonly_ &&
+                              parent_->account_to_be_pasted_from_ ==
+                                  parent_->account_ &&
+                              parent_->hasFilesToBePasted());
+    if (!proxy_index.isValid()) {
+        if (parent_->hasFilesToBePasted()) {
+            paste_only_menu_->exec(position);
+        }
+        return;
+    }
+
+    // printf ("paste action enabled: %s\n", paste_action_->isEnabled() ? "true": "false");
+
+    //
+    // map back to the source index from FileTableModel
+    //
+    const QModelIndex index = proxy_model_->mapToSource(proxy_index);
+    const int row = index.row();
+    const SeafDirent *dirent = source_model_->direntAt(row);
+    // if invalid dirent? no sure why it comes
+    if (!dirent)
+        return;
+
+    //
+    // find if the item is in the selection
+    // get selections
+    QItemSelectionModel *selections = this->selectionModel();
+    QModelIndexList selected = selections->selectedRows();
+    int pos;
+    for (pos = 0; pos < selected.size(); pos++)
+    {
+        if (row == proxy_model_->mapToSource(selected[pos]).row())
+            break;
+    }
+    //
+    // if the item is in the selection
+    // but it is a multi-selection
+    //
+    // the situation is different from the single-selection
+    // supports: download only (and cancel download action perhaps?)
+    //
+    if (pos != selected.size() && selected.size() != 1) {
+        item_.reset(NULL);
+
+        bool has_dir = false;
+        for (int i = 0; i != selected.size() ; i++) {
+            if (source_model_->direntAt(proxy_model_->mapToSource(selected[i]).row())->isDir()) {
+                has_dir = true;
+                break;
+            }
+        }
+
+        saveas_action_->setText(tr("&Save As To..."));
+        saveas_action_->setVisible(true);
+        saveas_action_->setEnabled(!has_dir);
+        lock_action_->setVisible(false);
+        rename_action_->setVisible(false);
+        share_action_->setVisible(false);
+        share_seafile_action_->setVisible(false);
+        share_to_user_action_->setVisible(false);
+        share_to_group_action_->setVisible(false);
+        // update_action_->setVisible(false);
+        cancel_download_action_->setVisible(false);
+        sync_subdirectory_action_->setVisible(false);
+
+        context_menu_->exec(position);
+
+        return;
+    }
+
+    //
+    // if the item is not in the selection
+    // and it is the single-selection situation
+    //
+    // it is the most common case
+    //
+
+    item_.reset(new SeafDirent(*dirent));
+
+    saveas_action_->setText(tr("&Save As..."));
+    saveas_action_->setVisible(true);
+    rename_action_->setVisible(true);
+    share_action_->setVisible(true);
+    share_seafile_action_->setVisible(true);
+    // update_action_->setVisible(true);
+    cancel_download_action_->setVisible(true);
+    cancel_download_action_->setVisible(false);
+    if (item_->readonly) {
+        move_action_->setEnabled(false);
+        rename_action_->setEnabled(false);
+        // update_action_->setEnabled(false);
+        remove_action_->setEnabled(false);
+    } else {
+        move_action_->setEnabled(true);
+        rename_action_->setEnabled(true);
+        // update_action_->setEnabled(true);
+        remove_action_->setEnabled(true);
+    }
+
+    if (item_->isDir()) {
+        lock_action_->setVisible(false);
+        // update_action_->setVisible(false);
+        saveas_action_->setEnabled(false);
+        sync_subdirectory_action_->setVisible(true);
+        share_to_user_action_->setVisible(true);
+        share_to_group_action_->setVisible(true);
+    } else {
+        if (item_->locked_by_me) {
+            lock_action_->setText(tr("Un&lock"));
+            lock_action_->setVisible(true);
+            move_action_->setEnabled(true);
+            remove_action_->setEnabled(true);
+            rename_action_->setEnabled(true);
+        } else if (item_->is_locked || item_->readonly) {
+            lock_action_->setVisible(false);
+            move_action_->setEnabled(false);
+            remove_action_->setEnabled(false);
+            rename_action_->setEnabled(false);
+        } else {
+            lock_action_->setText(tr("&Lock"));
+            lock_action_->setVisible(true);
+            move_action_->setEnabled(true);
+            remove_action_->setEnabled(true);
+            rename_action_->setEnabled(true);
+        }
+
+        // update_action_->setVisible(true);
+        saveas_action_->setEnabled(true);
+        sync_subdirectory_action_->setVisible(false);
+        share_to_user_action_->setVisible(false);
+        share_to_group_action_->setVisible(false);
+
+        if (TransferManager::instance()->getDownloadTask(parent_->repo_.id,
+            ::pathJoin(parent_->current_path_, dirent->name))) {
+            cancel_download_action_->setVisible(true);
+            saveas_action_->setVisible(false);
+        }
+    }
+
+    if (!parent_->account_.isPro() ||
+        parent_->repo_.owner != parent_->account_.username) {
+        share_to_user_action_->setVisible(false);
+        share_to_group_action_->setVisible(false);
+    }
+
+    QVariant file_status_v = source_model_->data(index, DirentCacheStatusRole);
+    AutoUpdateManager::FileStatus file_status = (AutoUpdateManager::FileStatus)file_status_v.toInt();
+    if (file_status == AutoUpdateManager::NOT_SYNCED) {
+        retry_upload_cached_file_action_->setVisible(true);
+        delete_local_version_action_->setVisible(true);
+        local_version_saveas_action_->setVisible(true);
+    }
+
+    QString localpath = DataManager::getLocalCacheFilePath(
+        parent_->repo_.id, ::pathJoin(parent_->current_path_, dirent->name));
+    if (QFileInfo(localpath).exists()) {
+        open_local_cache_folder_action_->setEnabled(true);
+    }
+
+    context_menu_->exec(position); // synchronously
+
+    //
+    // reset it to NULL, when the menu exec is done
+    //
+    item_.reset(NULL);
+}
+
+void FileTableView::onAboutToReset()
+{
+    item_.reset(NULL);
+}
+
+void FileTableView::onItemDoubleClicked(const QModelIndex& index)
+{
+    const SeafDirent *dirent =
+      source_model_->direntAt(proxy_model_->mapToSource(index).row());
+
+    if (dirent == NULL)
+        return;
+
+    emit direntClicked(*dirent);
+}
+
+void FileTableView::onRetryUploadCachedFile()
+{
+    const SeafDirent *dirent = getSelectedItemFromSource();
+    parent_->onGetDirentReupload(*dirent);
+}
+
+void FileTableView::onDeleteLocalVersion()
+{
+    const SeafDirent *dirent = getSelectedItemFromSource();
+
+    if (dirent == NULL) {
+        return;
+    }
+
+    emit deleteLocalVersion(*dirent);
+}
+
+void FileTableView::onLocalVersionSaveAs()
+{
+    const SeafDirent *dirent = getSelectedItemFromSource();
+
+    if (dirent == NULL) {
+        return;
+    }
+
+    emit localVersionSaveAs(*dirent);
+}
+
+void FileTableView::onSaveAs()
+{
+    if (item_ == NULL) {
+        const QList<const SeafDirent*> dirents = getSelectedItemsFromSource();
+        emit direntSaveAs(dirents);
+        return;
+    }
+
+    QList<const SeafDirent*> dirents;
+    dirents.push_back(item_.data());
+    emit direntSaveAs(dirents);
+}
+
+void FileTableView::onLock()
+{
+    const SeafDirent * item = item_.data();
+    if (item == NULL)
+        item = getSelectedItemFromSource();
+    if (!item || item->isDir() || item->readonly)
+        return;
+
+    emit direntLock(*item);
+}
+
+void FileTableView::onRename()
+{
+    if (item_ == NULL) {
+        const SeafDirent *selected_item = getSelectedItemFromSource();
+        if (selected_item && !selected_item->readonly)
+            emit direntRename(*selected_item);
+        return;
+    }
+
+    if (!item_->readonly)
+        emit direntRename(*item_);
+}
+
+void FileTableView::onRemove()
+{
+    bool has_readonly = false;
+    if (item_ == NULL) {
+        const QList<const SeafDirent*> dirents = getSelectedItemsFromSource();
+        Q_FOREACH(const SeafDirent* dirent, dirents)
+        {
+            if (dirent->readonly) {
+                has_readonly = true;
+                break;
+            }
+        }
+        if (!has_readonly) {
+            emit direntRemove(dirents);
+            return;
+        }
+    }
+    if (has_readonly || item_->readonly) {
+        seafApplet->messageBox(tr("Unable to remove readonly files"), this);
+    }
+
+    emit direntRemove(*item_);
+}
+
+void FileTableView::onShare()
+{
+    if (item_ == NULL) {
+        const SeafDirent *selected_item = getSelectedItemFromSource();
+        if (selected_item && selected_item->isFile())
+            emit direntShare(*selected_item);
+        return;
+    }
+    emit direntShare(*item_);
+}
+
+void FileTableView::onShareToUser()
+{
+    onShareToUserOrGroup(false);
+}
+
+void FileTableView::onShareToGroup()
+{
+    onShareToUserOrGroup(true);
+}
+
+void FileTableView::onShareToUserOrGroup(bool to_group)
+{
+    if (item_ == NULL) {
+        const SeafDirent *selected_item = getSelectedItemFromSource();
+        if (selected_item && selected_item->isDir())
+            emit direntShareToUserOrGroup(*selected_item, to_group);
+        return;
+    }
+    emit direntShareToUserOrGroup(*item_, to_group);
+}
+
+
+void FileTableView::onShareSeafile()
+{
+    if (item_ == NULL) {
+        const SeafDirent *selected_item = getSelectedItemFromSource();
+        if (selected_item && selected_item->isFile())
+            emit direntShareSeafile(*selected_item);
+        return;
+    }
+    emit direntShareSeafile(*item_);
+}
+
+
+void FileTableView::onUpdate()
+{
+    if (item_ == NULL) {
+        const SeafDirent *selected_item = getSelectedItemFromSource();
+        if (selected_item && selected_item->isFile() && !selected_item->readonly)
+            emit direntUpdate(*selected_item);
+        return;
+    }
+    if (!item_->readonly)
+        emit direntUpdate(*item_);
+}
+
+void FileTableView::onCopy()
+{
+    QStringList file_names;
+
+    if (item_ == NULL) {
+        const QList<const SeafDirent*> dirents = getSelectedItemsFromSource();
+        for (int i = 0; i < dirents.size(); i++) {
+            file_names.push_back(dirents[i]->name);
+        }
+    } else {
+        file_names.push_back(item_->name);
+    }
+
+
+    parent_->setFilesToBePasted(true, file_names);
+}
+
+void FileTableView::onMove()
+{
+    QStringList file_names;
+    bool has_readonly = false;
+
+    if (item_ == NULL) {
+        const QList<const SeafDirent*> dirents = getSelectedItemsFromSource();
+        for (int i = 0; i < dirents.size(); i++) {
+            // unable to move readonly files
+            if (dirents[i]->readonly) {
+                has_readonly = true;
+                break;
+            }
+            file_names.push_back(dirents[i]->name);
+        }
+    } else {
+        if (item_->readonly) {
+            has_readonly = true;
+        } else {
+            file_names.push_back(item_->name);
+        }
+    }
+
+    if (has_readonly) {
+        seafApplet->messageBox(tr("Unable to cut readonly files"), this);
+        return;
+    }
+
+    parent_->setFilesToBePasted(false, file_names);
+}
+
+void FileTableView::onCancelDownload()
+{
+    if (item_ == NULL) {
+        const QList<const SeafDirent*> dirents = getSelectedItemsFromSource();
+        for (int i = 0; i < dirents.size(); i++) {
+            emit cancelDownload(*dirents[i]);
+        }
+        return;
+    }
+    emit cancelDownload(*item_);
+}
+
+void FileTableView::onSyncSubdirectory()
+{
+    if (item_ && item_->isDir())
+        emit syncSubdirectory(item_->name);
+}
+
+void FileTableView::onOpenLocalCacheFolder()
+{
+    parent_->onOpenLocalCacheFolder();
+}
+
+void FileTableView::resizeEvent(QResizeEvent *event)
+{
+    QTableView::resizeEvent(event);
+    if (source_model_)
+        source_model_->onResize(event->size());
+}
+
+FileTableModel::FileTableModel(QObject *parent)
+    : QAbstractTableModel(parent),
+     name_column_width_(kFileNameColumnWidth)
+{
+    task_progress_timer_ = new QTimer(this);
+    connect(task_progress_timer_, SIGNAL(timeout()),
+            this, SLOT(updateDownloadInfo()));
+    connect(task_progress_timer_, SIGNAL(timeout()),
+            this, SLOT(updateFileCacheStatus()));
+    connect(ThumbnailService::instance(), SIGNAL(thumbnailUpdated(const QPixmap&, const QString&)),
+            this, SLOT(updateThumbnail(const QPixmap &, const QString&)));
+    task_progress_timer_->start(kRefreshProgressInterval);
+}
+
+void FileTableModel::setDirents(const QList<SeafDirent>& dirents)
+{
+    beginResetModel();
+    dirents_ = dirents;
+    progresses_.clear();
+    file_cache_statuses_.clear();
+    endResetModel();
+
+    updateFileCacheStatus();
+    updateDownloadInfo();
+    task_progress_timer_->start();
+}
+
+int FileTableModel::rowCount(const QModelIndex& parent) const
+{
+    return dirents_.size();
+}
+
+int FileTableModel::columnCount(const QModelIndex& parent) const
+{
+    return FILE_MAX_COLUMN;
+}
+
+QVariant FileTableModel::data(const QModelIndex & index, int role) const
+{
+    if (!index.isValid()) {
+        return QVariant();
+    }
+
+    const int column = index.column();
+    const int row = index.row();
+    const SeafDirent& dirent = dirents_[row];
+
+    if (role == Qt::DecorationRole && column == FILE_COLUMN_NAME) {
+        QIcon icon;
+
+        // These are the thumnail types supported by the server (as of 2019.1)
+        static QSet<QString> image_file_types = {"gif", "png", "jpg", "jpeg", "ico"};
+        if (dirent.isDir()) {
+            icon = dirent.readonly
+                       ? QIcon(":/images/files_v2/file_folder_readonly.png")
+                       : QIcon(":/images/files_v2/file_folder.png");
+        } else if (image_file_types.contains(QFileInfo(dirent.name).suffix().toLower())) {
+            FileBrowserDialog *dialog =
+                (FileBrowserDialog *)(QObject::parent());
+            ThumbnailService *service = ThumbnailService::instance();
+            return service->getThumbnail(
+                dialog->repo_.id,
+                ::pathJoin(dialog->current_path_, dirent.name),
+                dirent.id,
+                kColumnIconSize * globalDevicePixelRatio());
+        } else {
+            icon = QIcon(getIconByFileNameV2(dirent.name));
+        }
+        return icon.pixmap(kColumnIconSize, kColumnIconSize);
+    }
+
+    if (role == Qt::SizeHintRole) {
+        QSize qsize(kDefaultColumnWidth, kDefaultColumnHeight);
+        switch (column) {
+        case FILE_COLUMN_NAME:
+            qsize.setWidth(name_column_width_);
+            break;
+        case FILE_COLUMN_PROGRESS:
+        case FILE_COLUMN_SIZE:
+        case FILE_COLUMN_MTIME:
+            qsize.setWidth(name_column_width_);
+        case FILE_COLUMN_MODIFIER:
+        default:
+            break;
+        }
+        return qsize;
+    }
+
+    if (role == DirentLockStatusRole && column == FILE_COLUMN_NAME) {
+        if (dirent.locked_by_me) {
+            return (int)LOCKED_BY_ME;
+        } else if (dirent.is_locked) {
+            return (int)LOCKED_BY_OTHERS;
+        } else
+            return NOT_LOCKED;
+    }
+
+    if (role == DirentLockOwnerRole && column == FILE_COLUMN_NAME) {
+        return dirent.lock_owner;
+    }
+
+    if (role == Qt::ToolTipRole && column == FILE_COLUMN_NAME && !dirent.lock_owner.isEmpty()) {
+        return tr("locked by %1").arg(dirent.getLockOwnerDisplayString());
+    }
+
+    if (role == DirentCacheStatusRole) {
+        return file_cache_statuses_.contains(dirent.name)
+                   ? (int)file_cache_statuses_[dirent.name]
+                   : QVariant();
+    }
+
+    if (role != Qt::DisplayRole) {
+        return QVariant();
+    }
+
+    // DisplayRole
+
+    switch (column) {
+    case FILE_COLUMN_NAME:
+        return dirent.name;
+    case FILE_COLUMN_SIZE:
+        if (dirent.isDir())
+            return "";
+        return dirent.size;
+    case FILE_COLUMN_MTIME:
+        return dirent.mtime;
+    case FILE_COLUMN_MODIFIER:
+        return dirent.isDir() ? "" : dirent.modifier_name;
+    case FILE_COLUMN_PROGRESS:
+        return getTransferProgress(dirent);
+    default:
+        return QVariant();
+    }
+}
+
+QString FileTableModel::getTransferProgress(const SeafDirent& dirent) const
+{
+    return progresses_[dirent.name];
+}
+
+QVariant FileTableModel::headerData(int section,
+                                    Qt::Orientation orientation,
+                                    int role) const
+{
+    if (orientation == Qt::Vertical) {
+        return QVariant();
+    }
+
+    if (role == Qt::TextAlignmentRole) {
+        return Qt::AlignLeft + Qt::AlignVCenter;
+    }
+
+    if (role == Qt::DisplayRole) {
+        switch (section) {
+        case FILE_COLUMN_NAME:
+            return tr("Name");
+        case FILE_COLUMN_SIZE:
+            return tr("Size");
+        case FILE_COLUMN_MTIME:
+            return tr("Last Modified");
+        case FILE_COLUMN_MODIFIER:
+            return tr("Modifier");
+        default:
+            return QVariant();
+        }
+    }
+
+    if (role == Qt::FontRole) {
+        QFont font;
+        font.setPixelSize(12);
+        return font;
+    }
+
+    if (role == Qt::ForegroundRole) {
+        return QBrush(kFontColor);
+    }
+
+    if (role == Qt::SizeHintRole && section == FILE_COLUMN_NAME) {
+        if (dirents_.empty()) {
+            return QSize(name_column_width_, 0);
+        }
+    }
+
+    return QVariant();
+}
+
+const SeafDirent* FileTableModel::direntAt(int row) const
+{
+    if (row >= dirents_.size())
+        return NULL;
+
+    return &dirents_[row];
+}
+
+void FileTableModel::replaceItem(const QString &name, const SeafDirent &dirent)
+{
+    for (int pos = 0; pos != dirents_.size() ; pos++)
+        if (dirents_[pos].name == name) {
+            dirents_[pos] = dirent;
+            emit dataChanged(index(pos, 0), index(pos , FILE_MAX_COLUMN - 1));
+            break;
+        }
+}
+
+void FileTableModel::insertItem(int pos, const SeafDirent &dirent)
+{
+    if (pos > dirents_.size())
+        return;
+    beginInsertRows(QModelIndex(), pos, pos);
+    dirents_.insert(pos, dirent);
+    endInsertRows();
+}
+
+void FileTableModel::removeItemNamed(const QString &name)
+{
+    for (int pos = 0; pos != dirents_.size() ; pos++)
+        if (dirents_[pos].name == name) {
+            beginRemoveRows(QModelIndex(), pos, pos);
+            dirents_.removeAt(pos);
+            endRemoveRows();
+            break;
+        }
+}
+
+void FileTableModel::renameItemNamed(const QString &name, const QString &new_name)
+{
+    for (int pos = 0; pos != dirents_.size() ; pos++)
+        if (dirents_[pos].name == name) {
+            dirents_[pos].name = new_name;
+            emit dataChanged(index(pos, 0), index(pos , FILE_MAX_COLUMN - 1));
+            break;
+        }
+}
+
+void FileTableModel::onResize(const QSize &size)
+{
+    name_column_width_ = size.width() - kDefaultColumnSum + kFileNameColumnWidth;
+    // name_column_width_ should be always larger than kFileNameColumnWidth
+    if (dirents_.empty())
+        return;
+    emit dataChanged(index(0, FILE_COLUMN_NAME),
+                     index(dirents_.size()-1 , FILE_COLUMN_NAME));
+}
+
+void FileTableModel::updateDownloadInfo()
+{
+    FileBrowserDialog *dialog = (FileBrowserDialog *)(QObject::parent());
+    QList<FileDownloadTask*> tasks= TransferManager::instance()->getDownloadTasks(
+        dialog->repo_.id, dialog->current_path_);
+
+    progresses_.clear();
+
+    Q_FOREACH (FileDownloadTask *task, tasks) {
+        QString progress = task->progress().toString();
+        progresses_[::getBaseName(task->path())] = progress;
+    }
+
+    if (dirents_.empty())
+        return;
+    emit dataChanged(index(0, FILE_COLUMN_SIZE),
+                     index(dirents_.size() - 1 , FILE_COLUMN_SIZE));
+}
+
+
+void FileTableModel::updateFileCacheStatus()
+{
+    if (dirents_.empty())
+        return;
+
+    FileBrowserDialog *dialog = (FileBrowserDialog *)(QObject::parent());
+    QHash<QString, AutoUpdateManager::FileStatus> new_statues =
+        AutoUpdateManager::instance()->getFileStatusForDirectory(
+            dialog->account_.getSignature(),
+            dialog->repo_.id,
+            dialog->current_path_,
+            dirents_);
+
+    if (new_statues == file_cache_statuses_) {
+        return;
+    }
+
+    for (int pos = 0; pos != dirents_.size() ; pos++) {
+        const QString& name = dirents_[pos].name;
+        int new_status = new_statues.contains(name) ? (int)new_statues[name] : -1;
+        int old_status = file_cache_statuses_.contains(name) ? (int)file_cache_statuses_[name] : -1;
+        if (new_status != old_status) {
+            emit dataChanged(index(pos, FILE_COLUMN_NAME), index(pos , FILE_COLUMN_NAME));
+        }
+    }
+
+    file_cache_statuses_ = new_statues;
+    // printf ("repainting when file cache status is changed\n");
+    // emit dataChanged(index(0, FILE_COLUMN_NAME),
+    //                  index(dirents_.size() - 1 , FILE_COLUMN_NAME));
+}
+
+void FileTableModel::updateThumbnail(const QPixmap& thumbnail, const QString& path)
+{
+    const QString name = QFileInfo(path).fileName();
+    for (int pos = 0; pos != dirents_.size() ; pos++)
+        if (dirents_[pos].name == name) {
+            emit dataChanged(index(pos, 0), index(pos, FILE_COLUMN_NAME));
+            break;
+        }
+}
+
+bool FileTableSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
+{
+    bool is_dir_left = source_model_->direntAt(left.row())->isDir();
+    bool is_dir_right = source_model_->direntAt(right.row())->isDir();
+    if (is_dir_left != is_dir_right) {
+        return sortOrder() != Qt::AscendingOrder ? is_dir_right
+                                                 : !is_dir_right;
+    }
+    else if ((left.column() == FILE_COLUMN_NAME) &&
+             (right.column() == FILE_COLUMN_NAME)) {
+        const QString left_name = source_model_->direntAt(left.row())->name;
+        const QString right_name = source_model_->direntAt(right.row())->name;
+        return digitalCompare(left_name, right_name) < 0;
+    }
+    else {
+        return QSortFilterProxyModel::lessThan(left, right);
+    }
+}
diff --git a/src/filebrowser/file-table.h b/src/filebrowser/file-table.h
new file mode 100644 (file)
index 0000000..c7ad67b
--- /dev/null
@@ -0,0 +1,188 @@
+#ifndef SEAFILE_CLIENT_FILE_TABLE_H
+#define SEAFILE_CLIENT_FILE_TABLE_H
+
+#include <QTableView>
+#include <QStandardItem>
+#include <QAbstractTableModel>
+#include <QStyledItemDelegate>
+#include <QModelIndex>
+#include <QScopedPointer>
+#include <QSortFilterProxyModel>
+
+#include "api/server-repo.h"
+#include "seaf-dirent.h"
+#include "auto-update-mgr.h"
+
+#include "thumbnail-service.h"
+
+class DataManager;
+class ThumbnailService;
+
+class FileTableViewDelegate : public QStyledItemDelegate {
+    Q_OBJECT
+public:
+    FileTableViewDelegate(QObject *parent);
+    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+};
+
+class FileBrowserDialog;
+class FileTableModel;
+class FileTableView : public QTableView
+{
+    Q_OBJECT
+public:
+    FileTableView(QWidget *parent);
+    void setModel(QAbstractItemModel *model);
+
+signals:
+    void direntClicked(const SeafDirent& dirent);
+    void direntSaveAs(const QList<const SeafDirent*> &dirents);
+    void deleteLocalVersion(const SeafDirent& dirent);
+    void localVersionSaveAs(const SeafDirent& dirent);
+    void dropFile(const QStringList& paths);
+    void direntLock(const SeafDirent& dirent);
+    void direntRename(const SeafDirent& dirent);
+    void direntRemove(const SeafDirent& dirent);
+    void direntRemove(const QList<const SeafDirent*> &dirents);
+    void direntUpdate(const SeafDirent& dirent);
+    void direntShare(const SeafDirent& dirent);
+    void direntShareToUserOrGroup(const SeafDirent& dirent, bool to_group);
+    void direntShareSeafile(const SeafDirent& dirent);
+    void direntPaste();
+
+    void cancelDownload(const SeafDirent& dirent);
+    void syncSubdirectory(const QString& folder_name);
+
+private slots:
+    void onAboutToReset();
+    void onItemDoubleClicked(const QModelIndex& index);
+    void onRetryUploadCachedFile();
+    void onDeleteLocalVersion();
+    void onLocalVersionSaveAs();
+    void onSaveAs();
+    void onLock();
+    void onRename();
+    void onRemove();
+    void onShare();
+    void onShareToUser();
+    void onShareToGroup();
+    void onShareSeafile();
+    void onUpdate();
+    void onCopy();
+    void onMove();
+
+    void onCancelDownload();
+    void onSyncSubdirectory();
+    void onOpenLocalCacheFolder();
+
+private:
+    void setupContextMenu();
+
+    // \brief get current selection item
+    // it returns non-NULL if only we have one and only one item in seleceted
+    // the index it uses internally is mapped to source model
+    const SeafDirent *getSelectedItemFromSource();
+
+    // \brief get current selection items
+    // it returns the list of all of selected SeafDirents
+    // the indexes it uses internally is mapped to source model
+    QList<const SeafDirent *> getSelectedItemsFromSource();
+    void contextMenuEvent(QContextMenuEvent *event);
+    void resizeEvent(QResizeEvent *event);
+    void onShareToUserOrGroup(bool to_group);
+
+    Q_DISABLE_COPY(FileTableView)
+
+    // \brief the copy of the exact item where right click event occurs
+    // its lifetime is valid during the menu event and exec and invalid outside
+    QScopedPointer<const SeafDirent> item_;
+    QMenu *context_menu_;
+    QMenu *paste_only_menu_;
+    QAction *retry_upload_cached_file_action_;
+    QAction *delete_local_version_action_;
+    QAction *local_version_saveas_action_;
+    QAction *saveas_action_;
+    QAction *rename_action_;
+    QAction *remove_action_;
+    QAction *share_action_;
+    QAction *share_to_user_action_;
+    QAction *share_to_group_action_;
+    QAction *share_seafile_action_;
+    QAction *update_action_;
+    QAction *copy_action_;
+    QAction *move_action_;
+    QAction *paste_action_;
+    QAction *cancel_download_action_;
+    QAction *sync_subdirectory_action_;
+    QAction *lock_action_;
+    QAction *open_local_cache_folder_action_;
+    FileBrowserDialog *parent_;
+
+    // source model
+    FileTableModel *source_model_;
+    // proxy model
+    QSortFilterProxyModel *proxy_model_;
+};
+
+class FileTableModel : public QAbstractTableModel
+{
+    Q_OBJECT
+public:
+    FileTableModel(QObject *parent=0);
+
+    int rowCount(const QModelIndex& parent=QModelIndex()) const;
+    int columnCount(const QModelIndex& parent=QModelIndex()) const;
+    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
+
+    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+    void setDirents(const QList<SeafDirent>& dirents);
+    const QList<SeafDirent>& dirents() const { return dirents_; }
+
+    const SeafDirent* direntAt(int row) const;
+
+    void insertItem(int pos, const SeafDirent &dirent);
+    void appendItem(const SeafDirent &dirent) {
+        insertItem(rowCount(), dirent);
+    }
+    void replaceItem(const QString &name, const SeafDirent &dirent);
+    void removeItemNamed(const QString &name);
+    void renameItemNamed(const QString &name, const QString &new_name);
+
+    void onResize(const QSize &size);
+
+private slots:
+    void updateDownloadInfo();
+    void updateFileCacheStatus();
+    void updateThumbnail(const QPixmap& thumbnail, const QString& file_path);
+
+private:
+    Q_DISABLE_COPY(FileTableModel)
+
+    QString getTransferProgress(const SeafDirent& dirent) const;
+
+    QList<SeafDirent> dirents_;
+
+    QHash<QString, QString> progresses_;
+    QHash<QString, AutoUpdateManager::FileStatus> file_cache_statuses_;
+
+    int name_column_width_;
+
+    QTimer *task_progress_timer_;
+};
+
+class FileTableSortFilterProxyModel : public QSortFilterProxyModel {
+    Q_OBJECT
+public:
+    FileTableSortFilterProxyModel(FileTableModel *parent)
+        : QSortFilterProxyModel(parent), source_model_(parent) {
+        setSortCaseSensitivity(Qt::CaseInsensitive);
+    }
+    bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
+
+private:
+    FileTableModel* source_model_;
+};
+
+
+#endif  // SEAFILE_CLIENT_FILE_TABLE_H
diff --git a/src/filebrowser/progress-dialog.cpp b/src/filebrowser/progress-dialog.cpp
new file mode 100644 (file)
index 0000000..3608be8
--- /dev/null
@@ -0,0 +1,300 @@
+#include <QMessageBox>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QProgressBar>
+#include <QPushButton>
+#include <QDesktopServices>
+#include <QDebug>
+#include <climits>
+
+#include "utils/utils.h"
+#include "progress-dialog.h"
+#include "seafile-applet.h"
+#include "transfer-mgr.h"
+
+namespace
+{
+const char* kQueryIndexUrl = "idx_progress";
+} // namespace
+
+
+FileBrowserProgressDialog::FileBrowserProgressDialog(FileNetworkTask *task, QWidget *parent)
+        : QProgressDialog(parent),
+          task_(task),
+          progress_request_(NULL),
+          index_progress_timer_(new QTimer(this)),
+          task_finished_(false)
+{
+    initUI();
+    initTaskInfo();
+
+    connect(index_progress_timer_, SIGNAL(timeout()), this, SLOT(onQueryUpdate()));
+
+    connect(task_, SIGNAL(progressUpdate(qint64, qint64)),
+            this, SLOT(onProgressUpdate(qint64, qint64)));
+    connect(task_, SIGNAL(nameUpdate(QString)),
+            this, SLOT(onCurrentNameUpdate(QString)));
+    connect(task_, SIGNAL(finished(bool)), this, SLOT(onTaskFinished(bool)));
+    connect(task_, SIGNAL(retried(int)), this, SLOT(initTaskInfo()));
+    connect(this, SIGNAL(canceled()), this, SLOT(cancel()));
+
+    if (task_->type() == FileNetworkTask::Upload) {
+        FileUploadTask *upload_task = (FileUploadTask *)task_;
+        connect(upload_task, SIGNAL(oneFileFailed(const QString&, bool)),
+                this, SLOT(onOneFileUploadFailed(const QString&, bool)));
+    }
+}
+
+void FileBrowserProgressDialog::initUI()
+{
+    setWindowModality(Qt::NonModal);
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+    setWindowIcon(QIcon(":/images/seafile.png"));
+
+    QVBoxLayout *layout_ = new QVBoxLayout;
+    progress_bar_ = new QProgressBar;
+    description_label_ = new QLabel;
+
+    layout_->addWidget(description_label_);
+    layout_->addWidget(progress_bar_);
+
+    QHBoxLayout *hlayout_ = new QHBoxLayout;
+    more_details_label_ = new QLabel;
+    more_details_label_->setText(tr("Pending"));
+    cancel_button_ = new QPushButton(tr("Cancel"));
+    QWidget *spacer = new QWidget;
+    spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+    hlayout_->addWidget(more_details_label_);
+    hlayout_->addWidget(spacer);
+    hlayout_->addWidget(cancel_button_);
+    hlayout_->setContentsMargins(-1, 0, -1, 6);
+    layout_->setContentsMargins(-1, 0, -1, 6);
+    layout_->addLayout(hlayout_);
+
+    setLayout(layout_);
+    setLabel(description_label_);
+    setBar(progress_bar_);
+    setCancelButton(cancel_button_);
+}
+
+FileBrowserProgressDialog::~FileBrowserProgressDialog()
+{
+    if (progress_request_ != NULL)
+        progress_request_->deleteLater();
+}
+
+void FileBrowserProgressDialog::initTaskInfo()
+{
+    task_finished_ = false;
+    if (task_->canceled()) {
+        return;
+    }
+    QString title, label;
+    if (task_->type() == FileNetworkTask::Upload) {
+        title = tr("Upload");
+        label = tr("Uploading %1");
+    } else {
+        title = tr("Download");
+        label = tr("Downloading %1");
+    }
+    setWindowTitle(title);
+    setLabelText(label.arg(QFileInfo(task_->localFilePath()).fileName()));
+
+    more_details_label_->setText("");
+
+    setMaximum(0);
+    setValue(0);
+}
+
+void FileBrowserProgressDialog::onCurrentNameUpdate(QString current_name)
+{
+    QString label = tr("Uploading %1");
+    setLabelText(label.arg(current_name));
+}
+
+void FileBrowserProgressDialog::onProgressUpdate(qint64 processed_bytes, qint64 total_bytes)
+{
+    // Skip the updates if the task has been cancelled, because we may already
+    // have already rejected this dialog.
+    if (task_->canceled()) {
+        return;
+    }
+    // if the value is less than the maxmium, this dialog will close itself
+    // add this guard for safety
+    if (processed_bytes >= total_bytes)
+        total_bytes = processed_bytes + 1;
+
+    if (total_bytes > INT_MAX) {
+        if (maximum() != INT_MAX)
+            setMaximum(INT_MAX);
+
+        // Avoid overflow
+        double progress = double(processed_bytes) * INT_MAX / total_bytes;
+        setValue((int)progress);
+    } else {
+        if (maximum() != total_bytes)
+            setMaximum(total_bytes);
+
+        setValue(processed_bytes);
+    }
+
+    more_details_label_->setText(tr("%1 of %2")
+                            .arg(::readableFileSizeV2(processed_bytes))
+                            .arg(::readableFileSizeV2(total_bytes)));
+}
+
+void FileBrowserProgressDialog::onTaskFinished(bool success)
+{
+    task_finished_ = true;
+    // printf ("FileBrowserProgressDialog: onTaskFinished\n");
+    if (task_->canceled()) {
+        return;
+    }
+
+    cancel_button_->setVisible(false);
+
+    // When this "onTaskFinished" slot is called, the task may NOT
+    // have really finished yet, i.e. if we configured "async save" on
+    // server, we need to query the async save progress and only close
+    // the dialog after the async save is done.
+    //
+    // TODO: Right now the async save progress query is implemented
+    // here, but ideally it should be implemented inside the
+    // ReliablePostFileTask class for better encapsulation.
+    progerss_id_ = task_->oid();
+
+    //https://dev.seafile.com/seafhttp/upload-api/b7443978-42cf-4cc6-87bf-add0fc7ad6e3
+    //https://dev.seafile.com/seafhttp/idx_progress
+    progress_url_ = ::urlJoin(QUrl(task_->url().toString(QUrl::PrettyDecoded).
+                                   section("upload", 0, 0)), kQueryIndexUrl);
+    if (success) {
+        // printf ("progress dialog: task success\n");
+
+        //Judge "-" as a task id or a file id
+        //Compatible with new and old server versions
+        if (progerss_id_.contains("-")) {
+            onQueryUpdate();
+            index_progress_timer_->start(3000);
+        } else {
+            accept();
+        }
+    } else {
+        // printf ("progress dialog: task failed\n");
+        reject();
+    }
+}
+
+void FileBrowserProgressDialog::onQueryUpdate()
+{
+    if (progress_request_) {
+        progress_request_->deleteLater();
+        progress_request_ = NULL;
+    }
+
+    progress_request_ = new GetIndexProgressRequest(progress_url_, progerss_id_);
+    connect(progress_request_, SIGNAL(success(const ServerIndexProgress&)),
+            this, SLOT(onQuerySuccess(const ServerIndexProgress&)));
+    connect(progress_request_, SIGNAL(failed(const ApiError& error)),
+            this, SLOT(onQueryFailed(const ApiError& error)));
+
+    progress_request_->send();
+}
+
+void FileBrowserProgressDialog::onQuerySuccess(const ServerIndexProgress &result)
+{
+    setLabelText(tr("Saving"));
+    more_details_label_->setText(tr("%1 of %2")
+                            .arg(::readableFileSizeV2(result.indexed))
+                            .arg(::readableFileSizeV2(result.total)));
+    if (result.status == 0) {
+        index_progress_timer_->stop();
+        accept();
+    } else if (result.status == -1) {
+        index_progress_timer_->stop();
+        seafApplet->warningBox(tr("File save failed"), this);
+        reject();
+    }
+}
+
+void FileBrowserProgressDialog::onQueryFailed(const ApiError& error)
+{
+    qWarning("get index progress request error: %s", error.toString().toUtf8().data());
+    // when http error occur stop index_progress_timer.
+    if (error.type() == ApiError::HTTP_ERROR) {
+        index_progress_timer_->stop();
+        seafApplet->warningBox(tr("Index progress request error %1").arg(error.httpErrorCode()));
+        reject();
+    }
+}
+
+void FileBrowserProgressDialog::cancel()
+{
+    if (task_finished_ || task_->canceled()) {
+        return;
+    }
+    if (task_->type() == FileNetworkTask::Upload) {
+        task_->cancel();
+    } else {
+        // For download tasks we need to go through the transfer manager
+        TransferManager::instance()->cancelDownload(task_->repoId(), task_->path());
+    }
+    reject();
+}
+
+void FileBrowserProgressDialog::onOneFileUploadFailed(const QString &filename,
+                                                      bool single_file)
+{
+    if (task_->canceled()) {
+        return;
+    }
+
+    FileUploadTask *upload_task = (FileUploadTask *)task_;
+
+    QString msg =
+        tr("Failed to upload file \"%1\", do you want to retry?").arg(filename);
+    ActionOnFailure choice = retryOrSkipOrAbort(msg, single_file);
+
+    switch (choice) {
+        case ActionRetry:
+            upload_task->continueWithFailedFile(true);
+            break;
+        case ActionSkip:
+            upload_task->continueWithFailedFile(false);
+            break;
+        case ActionAbort:
+            cancel();
+            break;
+    }
+}
+
+FileBrowserProgressDialog::ActionOnFailure
+FileBrowserProgressDialog::retryOrSkipOrAbort(const QString& msg, bool single_file)
+{
+    QMessageBox box(this);
+    box.setText(msg);
+    box.setWindowTitle(getBrand());
+    box.setIcon(QMessageBox::Question);
+
+    QPushButton *yes_btn = box.addButton(tr("Retry"), QMessageBox::YesRole);
+    QPushButton *no_btn = nullptr;
+    if (!single_file) {
+        // If this is single file upload/update, we only show "retry" and
+        // "abort".
+        no_btn = box.addButton(tr("Skip"), QMessageBox::NoRole);
+    }
+    box.addButton(tr("Abort"), QMessageBox::RejectRole);
+
+
+    box.setDefaultButton(yes_btn);
+    box.exec();
+    QAbstractButton *btn = box.clickedButton();
+    if (btn == yes_btn) {
+        return ActionRetry;
+    } else if (btn == no_btn) {
+        return ActionSkip;
+    }
+
+    return ActionAbort;
+}
diff --git a/src/filebrowser/progress-dialog.h b/src/filebrowser/progress-dialog.h
new file mode 100644 (file)
index 0000000..377d84f
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_PROGRESS_DIALOG_H
+#define SEAFILE_CLIENT_FILE_BROWSER_PROGRESS_DIALOG_H
+
+#include <QProgressDialog>
+#include <QObject>
+#include <QTimer>
+
+#include "tasks.h"
+
+class QProgressBar;
+class QLabel;
+
+
+class FileBrowserProgressDialog : public QProgressDialog {
+    Q_OBJECT
+public:
+    FileBrowserProgressDialog(FileNetworkTask *task, QWidget *parent=0);
+    ~FileBrowserProgressDialog();
+
+    typedef enum {
+        ActionRetry = 0,
+        ActionSkip,
+        ActionAbort,
+    } ActionOnFailure;
+
+public slots:
+    void cancel();
+
+private slots:
+    void onProgressUpdate(qint64 processed_bytes, qint64 total_bytes);
+    void onCurrentNameUpdate(QString current_name);
+    void onTaskFinished(bool success);
+    void initTaskInfo();
+    void onOneFileUploadFailed(const QString& filename, bool single_file);
+    void onQueryUpdate();
+    void onQuerySuccess(const ServerIndexProgress& result);
+    void onQueryFailed(const ApiError& error);
+    ActionOnFailure retryOrSkipOrAbort(const QString& msg, bool single_file);
+
+private:
+    void initUI();
+
+    FileNetworkTask* task_;
+    QPushButton *cancel_button_;
+    QLabel *description_label_;
+    QLabel *more_details_label_;
+    QProgressBar *progress_bar_;
+    QUrl progress_url_;
+    QString progerss_id_;
+    GetIndexProgressRequest *progress_request_;
+    QTimer *index_progress_timer_;
+    bool task_finished_;
+};
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_PROGRESS_DIALOG_H
diff --git a/src/filebrowser/reliable-upload.cpp b/src/filebrowser/reliable-upload.cpp
new file mode 100644 (file)
index 0000000..0857b04
--- /dev/null
@@ -0,0 +1,485 @@
+#include <assert.h>
+
+#include <QBuffer>
+#include <QThread>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QHttpMultiPart>
+#include <QHttpPart>
+#include <QFile>
+#include <QSslError>
+#include <QSslConfiguration>
+#include <QSslCertificate>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "certs-mgr.h"
+#include "api/api-error.h"
+#include "configurator.h"
+#include "network-mgr.h"
+#include "reliable-upload.h"
+
+namespace {
+
+const char *kParentDirParam = "form-data; name=\"parent_dir\"";
+const char *kTargetFileParam = "form-data; name=\"target_file\"";
+const char *kRelativePathParam = "form-data; name=\"relative_path\"";
+const char *kFileParamTemplate = "form-data; name=\"file\"; filename=\"%1\"";
+const char *kContentTypeApplicationOctetStream = "application/octet-stream";
+const char *kFileNameHeaderTemplate = "attachment; filename=\"%1\"";
+
+// 100MB
+const quint32 kMinimalSizeForChunkedUploads = 100 * 1024 * 1024;
+// 1MB
+const quint32 kUploadChunkSize = 1024 * 1024;
+
+// void printThread(const QString& prefix)
+// {
+//     printf ("%s %p\n", toCStr(prefix + " "), QThread::currentThreadId());
+// }
+
+} // namesapce
+
+ReliablePostFileTask::ReliablePostFileTask(const Account &account,
+                                           const QString &repo_id,
+                                           const QUrl &url,
+                                           const QString &parent_dir,
+                                           const QString &local_path,
+                                           const QString &name,
+                                           const bool use_upload,
+                                           const bool accept_user_confirmation)
+    : FileServerTask(url, local_path),
+      account_(account),
+      repo_id_(repo_id),
+      part_of_folder_upload_(false),
+      parent_dir_(parent_dir),
+      file_(nullptr),
+      name_(name),
+      use_upload_(use_upload)
+{
+    current_offset_ = 0;
+    current_chunk_size_ = 0;
+    done_ = 0;
+    total_size_ = 0;
+    // Chunked uploading is disabled for updating an existing file
+    resumable_ = use_upload;
+    accept_user_confirmation_ = accept_user_confirmation;
+}
+
+ReliablePostFileTask::ReliablePostFileTask(const QUrl &url,
+                                           const QString &parent_dir,
+                                           const QString &local_path,
+                                           const QString &name,
+                                           const QString &relative_path)
+    : FileServerTask(url, local_path),
+      account_(Account()),
+      repo_id_(QString()),
+      part_of_folder_upload_(true),
+      parent_dir_(parent_dir),
+      file_(nullptr),
+      name_(name),
+      use_upload_(true),
+      relative_path_(relative_path)
+{
+    current_offset_ = 0;
+    current_chunk_size_ = 0;
+    done_ = 0;
+    total_size_ = 0;
+    resumable_ = false;
+
+    // This constructor is called by the PostFilesTask, which handles user
+    // confirmation and retry itself.
+    accept_user_confirmation_ = false;
+}
+
+ReliablePostFileTask::~ReliablePostFileTask()
+{
+    if (file_) {
+        file_->close();
+        file_ = nullptr;
+    }
+}
+
+bool ReliablePostFileTask::retryEnabled()
+{
+    return true;
+}
+
+void ReliablePostFileTask::prepare()
+{
+    if (file_) {
+        // In case of retry
+        delete file_;
+    }
+    file_ = new QFile(local_path_);
+    file_->setParent(this);
+    if (!file_->exists()) {
+        setError(FileNetworkTask::FileIOError, tr("File does not exist"));
+        emit finished(false);
+        return;
+    }
+    if (!file_->open(QIODevice::ReadOnly)) {
+        setError(FileNetworkTask::FileIOError, tr("File does not exist"));
+        emit finished(false);
+        return;
+    }
+    total_size_ = file_->size();
+}
+
+bool ReliablePostFileTask::useResumableUpload() const
+{
+    return resumable_ && total_size_ > kMinimalSizeForChunkedUploads;
+}
+
+void ReliablePostFileTask::sendRequest()
+{
+    if (useResumableUpload()) {
+        checkUploadedBytes();
+    } else {
+        startPostFileTask();
+    }
+}
+
+void ReliablePostFileTask::checkUploadedBytes()
+{
+    file_uploaded_bytes_req_.reset(
+        new GetFileUploadedBytesRequest(account_, repo_id_, parent_dir_, name_));
+
+    connect(file_uploaded_bytes_req_.data(), SIGNAL(success(bool, quint64)),
+            this, SLOT(onGetFileUploadedBytesSuccess(bool, quint64)));
+    connect(file_uploaded_bytes_req_.data(), SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetFileUploadedBytesFailed(const ApiError&)));
+    file_uploaded_bytes_req_->send();
+}
+
+void ReliablePostFileTask::onGetFileUploadedBytesSuccess(bool support_chunked_uploading, quint64 uploaded_bytes)
+{
+    if (!support_chunked_uploading) {
+        resumable_ = false;
+        current_offset_ = 0;
+    } else {
+        current_offset_ = uploaded_bytes;
+    }
+
+    startPostFileTask();
+}
+
+void ReliablePostFileTask::onGetFileUploadedBytesFailed(const ApiError& error)
+{
+    resumable_ = false;
+    current_offset_ = 0;
+    // printf("file %s: get uploaded bytes failed with %s\n",
+    //        name_.toUtf8().data(),
+    //        error.toString().toUtf8().data());
+    startPostFileTask();
+}
+
+void ReliablePostFileTask::startPostFileTask()
+{
+    // Update the progress when retrying
+    emit progressUpdate(current_offset_, total_size_);
+
+    createPostFileTask();
+    QMetaObject::invokeMethod(task_.data(), "start");
+}
+
+void ReliablePostFileTask::createPostFileTask()
+{
+    if (part_of_folder_upload_) {
+        // File uploading as part of directory uploading: does not support
+        // chunked uploads
+        task_.reset(new PostFileTask(url_,
+                                     parent_dir_,
+                                     local_path_,
+                                     file_,
+                                     name_,
+                                     relative_path_,
+                                     total_size_));
+    } else {
+        QUrl url = url_;
+        if (useResumableUpload()) {
+            current_chunk_size_ =
+                qMin((quint64)kUploadChunkSize, total_size_ - current_offset_);
+            // This is a quick fix when the server hasn't implemented chunking
+            // support in /upload/api/ endpoint yet.
+            url = QUrl(url_.toString(QUrl::PrettyDecoded).replace("/upload-api/", "/upload-aj/"));
+            // printf ("old url: %s\n", url_.toEncoded().data());
+            // printf ("new url: %s\n", url.toEncoded().data());
+            need_idx_progress_ = true;
+        } else {
+            need_idx_progress_ = false;
+        }
+        // For emulating upload errors
+        // url = QUrl(url_.toString(QUrl::PrettyDecoded).replace("1", "x").replace("2", "x"));
+        task_.reset(new PostFileTask(url,
+                                     parent_dir_,
+                                     local_path_,
+                                     file_,
+                                     name_,
+                                     use_upload_,
+                                     total_size_,
+                                     current_offset_,
+                                     current_chunk_size_,
+                                     need_idx_progress_));
+    }
+    setupSignals();
+    // printThread("reliable task is in thread");
+    task_.data()->moveToThread(FileNetworkTask::worker_thread_);
+}
+
+void ReliablePostFileTask::setupSignals()
+{
+    connect(task_.data(), SIGNAL(finished(bool)), this, SLOT(onPostFileTaskFinished(bool)));
+    connect(task_.data(),
+            SIGNAL(progressUpdate(qint64, qint64)),
+            this,
+            SLOT(onPostFileTaskProgressUpdate(qint64, qint64)));
+}
+
+void ReliablePostFileTask::handlePostFileTaskFailure()
+{
+    if (!canceled_ && accept_user_confirmation_) {
+        emit oneFileFailed(name_, true);
+    } else {
+        emit finished(false);
+    }
+}
+
+void ReliablePostFileTask::continueWithFailedFile(bool retry, const QString& link)
+{
+    // retry=false mean skip the current file and continue with the
+    // next one. It is only used in PostFilesTask which contains a
+    // list of files to be uploaded.
+    assert(retry);
+    start();
+}
+
+void ReliablePostFileTask::onPostFileTaskFinished(bool result)
+{
+    // First check if we should retry on failure
+    if (!result) {
+        if (task_->error() == FileNetworkTask::ApiRequestError && maybeRetry()) {
+            return;
+        }
+    }
+
+    http_error_code_ = task_->httpErrorCode();
+    error_string_ = task_->errorString();
+    error_ = task_->error();
+
+    if (!useResumableUpload()) {
+        // Simple upload
+        if (result) {
+            emit finished(true);
+        } else {
+            handlePostFileTaskFailure();
+        }
+        return;
+    }
+
+    // printf ("total_size: %llu, offset: %llu, chunk: %u\n", total_size_, current_offset_, current_chunk_size_);
+
+    // Resumable upload
+    if (!result) {
+        handlePostFileTaskFailure();
+        return;
+    }
+
+    // A chunk is successfully uploaded to the server
+    if (current_offset_ + current_chunk_size_ >= total_size_) {
+        emit finished(true);
+        return;
+    } else {
+        current_offset_ += current_chunk_size_;
+        // Continue with next chunk
+        startPostFileTask();
+    }
+}
+
+void ReliablePostFileTask::onPostFileTaskProgressUpdate(qint64 done, qint64 total)
+{
+    done_ = current_offset_ + done;
+    emit progressUpdate(done_, total_size_);
+}
+
+const QString& ReliablePostFileTask::oid() const
+{
+    return task_->oid();
+}
+
+void ReliablePostFileTask::cancel()
+{
+    // Must cancel itself first to set the canceled_ flag to avoid it being
+    // retried
+    FileServerTask::cancel();
+    if (task_) {
+        QMetaObject::invokeMethod(task_.data(), "cancel");
+    }
+}
+
+void ReliablePostFileTask::onHttpRequestFinished()
+{
+    // Nothing to do. The actual POST http request is managed by PostFileTask
+}
+
+PostFileTask::PostFileTask(const QUrl& url,
+                           const QString& parent_dir,
+                           const QString& local_path,
+                           QFile *file,
+                           const QString& name,
+                           const bool use_upload,
+                           quint64 total_size,
+                           quint64 start_offset,
+                           quint32 chunk_size,
+                           const bool need_idx_progress)
+    : FileServerTask(url, local_path),
+      parent_dir_(parent_dir),
+      file_(file),
+      name_(name),
+      use_upload_(use_upload),
+      total_size_(total_size),
+      start_offset_(start_offset),
+      chunk_size_(chunk_size),
+      need_idx_progress_(need_idx_progress)
+{
+}
+
+PostFileTask::PostFileTask(const QUrl& url,
+                           const QString& parent_dir,
+                           const QString& local_path,
+                           QFile *file,
+                           const QString& name,
+                           const QString& relative_path,
+                           quint64 total_size)
+    : FileServerTask(url, local_path),
+      parent_dir_(parent_dir),
+      file_(file),
+      name_(name),
+      use_upload_(true),
+      relative_path_(relative_path),
+      total_size_(total_size),
+      start_offset_(0),
+      chunk_size_(-1),
+      need_idx_progress_(false)
+{
+}
+
+PostFileTask::~PostFileTask()
+{
+}
+
+void PostFileTask::prepare()
+{
+    // printThread("post file task is in thread");
+}
+
+bool PostFileTask::isChunked() const
+{
+    return chunk_size_ > 0;
+}
+
+/**
+ * This member function may be called in two places:
+ * 1. when task is first started
+ * 2. when the request is redirected
+ */
+void PostFileTask::sendRequest()
+{
+    QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType, this);
+    // parent_dir param
+    QHttpPart parentdir_part, file_part;
+    if (use_upload_) {
+        parentdir_part.setHeader(QNetworkRequest::ContentDispositionHeader,
+                                 kParentDirParam);
+        parentdir_part.setBody(parent_dir_.toUtf8());
+    } else {
+        parentdir_part.setHeader(QNetworkRequest::ContentDispositionHeader,
+                                 kTargetFileParam);
+        parentdir_part.setBody(::pathJoin(parent_dir_, name_).toUtf8());
+    }
+    multipart->append(parentdir_part);
+
+    // "relative_path" param
+    if (!relative_path_.isEmpty()) {
+        QHttpPart part;
+        part.setHeader(QNetworkRequest::ContentDispositionHeader,
+                       kRelativePathParam);
+        part.setBody(relative_path_.toUtf8());
+        multipart->append(part);
+    }
+
+    // "file" param
+    file_part.setHeader(QNetworkRequest::ContentDispositionHeader,
+                        QString(kFileParamTemplate).arg(name_).toUtf8());
+    file_part.setHeader(QNetworkRequest::ContentTypeHeader,
+                        kContentTypeApplicationOctetStream);
+
+    if (isChunked()) {
+        // MMap the chunk to read the chunk content from the file
+        uchar *buf = file_->map(start_offset_, chunk_size_);
+        if (!buf) {
+            setError(FileNetworkTask::FileIOError, "Failed to read file content");
+            emit finished(false);
+            return;
+        }
+        QBuffer *buffer = new QBuffer();
+        buffer->setParent(this);
+        // This would copy the mmaped file content to the QBuffer right now
+        buffer->setData(QByteArray(reinterpret_cast<const char*>(buf), chunk_size_));
+        buffer->open(QIODevice::ReadOnly);
+        file_->unmap(buf);
+        file_part.setBodyDevice(buffer);
+    } else {
+        file_part.setBodyDevice(file_);
+    }
+    multipart->append(file_part);
+
+    // "need_idx_progress" param
+    if (need_idx_progress_) {
+        url_ = ::includeQueryParams(url_, {{"need_idx_progress", "true"}});
+    }
+
+    QNetworkRequest request(url_);
+    request.setRawHeader("Content-Type",
+                         "multipart/form-data; boundary=" + multipart->boundary());
+    if (isChunked()) {
+        setContentRangeHeader(&request);
+    }
+
+    reply_ = getQNAM()->post(request, multipart);
+
+    connect(reply_, SIGNAL(sslErrors(const QList<QSslError>&)),
+            this, SLOT(onSslErrors(const QList<QSslError>&)));
+    connect(reply_, SIGNAL(finished()), this, SLOT(httpRequestFinished()));
+    connect(reply_, SIGNAL(uploadProgress(qint64,qint64)),
+            this, SIGNAL(progressUpdate(qint64, qint64)));
+}
+
+void PostFileTask::setContentRangeHeader(QNetworkRequest *request)
+{
+    auto range_header = QString("bytes %1-%2/%3")
+                            .arg(QString::number(start_offset_),
+                                 QString::number(start_offset_ + chunk_size_ - 1),
+                                 QString::number(file_->size()));
+    // printf("range_header = %s\n", range_header.toUtf8().data());
+    request->setRawHeader("Content-Range", range_header.toUtf8());
+    request->setRawHeader("Content-Disposition",
+                          QString(kFileNameHeaderTemplate).arg(name_).toUtf8());
+}
+
+void PostFileTask::onHttpRequestFinished()
+{
+    if (canceled_) {
+        return;
+    }
+
+    if (handleHttpRedirect()) {
+        return;
+    }
+
+    oid_ = reply_->readAll();
+
+    emit finished(true);
+}
diff --git a/src/filebrowser/reliable-upload.h b/src/filebrowser/reliable-upload.h
new file mode 100644 (file)
index 0000000..fb322cf
--- /dev/null
@@ -0,0 +1,144 @@
+#ifndef SEAFILE_CLIETN_FILEBROWSER_RELIABLE_TAKS_H
+#define SEAFILE_CLIETN_FILEBROWSER_RELIABLE_TAKS_H
+
+#include "tasks.h"
+
+class PostFileTask;
+class ApiError;
+class QBuffer;
+
+// A wrapper of the PostFileTask class to upload a single file. It adds extra
+// features like:
+// 1. retrying
+// 2. chunked uploads: send big files in 1MB chunks, and each chunk is sent with a PostFileTask
+// 3. aggregate and show correct progress when retring and chunked uploads
+//
+// This makes PostFileTask very simple - it only need to focus on uploading a
+// single piece of a file, with all uppler level features like retrying and
+// chunking implemented here.
+class ReliablePostFileTask : public FileServerTask {
+    Q_OBJECT
+public:
+    // Instance created using this constructor would use chunked uploads (if
+    // the server supports it).
+    ReliablePostFileTask(const Account &account,
+                         const QString &repo_id,
+                         const QUrl &url,
+                         const QString &parent_dir,
+                         const QString &local_path,
+                         const QString &name,
+                         const bool use_upload,
+                         const bool accept_user_confirmation);
+
+    // Instance created using this constructor *would not* use chunked uploads.
+    // This is used for uploading files in folder uploads.
+    ReliablePostFileTask(const QUrl &url,
+                         const QString &parent_dir,
+                         const QString &local_path,
+                         const QString &name,
+                         const QString &relative_path);
+
+    ~ReliablePostFileTask();
+
+    virtual const QString &oid() const;
+    virtual void continueWithFailedFile(bool retry, const QString& link);
+
+public slots:
+    void cancel();
+
+protected:
+    bool retryEnabled();
+    void prepare();
+    void sendRequest();
+    void onHttpRequestFinished();
+    void checkUploadedBytes();
+
+private slots:
+    void onGetFileUploadedBytesSuccess(bool support_chunked_uploading, quint64 uploaded_bytes);
+    void onGetFileUploadedBytesFailed(const ApiError& error);
+    void onPostFileTaskFinished(bool result);
+    void onPostFileTaskProgressUpdate(qint64 done, qint64 total);
+
+private:
+    void setContentRangeHeader(QNetworkRequest *request);
+    void setupSignals();
+    void createPostFileTask();
+    void startPostFileTask();
+    bool useResumableUpload() const;
+    void handlePostFileTaskFailure();
+
+    const Account account_;
+    const QString repo_id_;
+    const bool part_of_folder_upload_;
+
+    const QString parent_dir_;
+    QFile *file_;
+    const QString name_;
+    const bool use_upload_;
+    const QString relative_path_;
+
+    quint64 done_;
+    quint64 total_size_;
+
+    //---------------------------------
+    // Used for resumable (chunk) uploads
+    //---------------------------------
+    bool resumable_;
+    quint64 current_offset_;
+    quint32 current_chunk_size_;
+    bool need_idx_progress_;
+
+    // The underlying task that sends the POST file request
+    QScopedPointer<PostFileTask, doDeleteLater<PostFileTask> > task_;
+    QScopedPointer<GetFileUploadedBytesRequest, doDeleteLater<GetFileUploadedBytesRequest> > file_uploaded_bytes_req_;
+
+    bool accept_user_confirmation_;
+};
+
+class PostFileTask : public FileServerTask {
+    Q_OBJECT
+    friend class ReliablePostFileTask;
+public:
+    PostFileTask(const QUrl& url,
+                 const QString& parent_dir,
+                 const QString& local_path,
+                 QFile *file,
+                 const QString& name,
+                 const bool use_upload,
+                 quint64 total_size,
+                 quint64 start_offset,
+                 quint32 chunk_size,
+                 const bool need_idx_progress);
+
+    PostFileTask(const QUrl& url,
+                 const QString& parent_dir,
+                 const QString& local_path,
+                 QFile *file,
+                 const QString& name,
+                 const QString& relative_path,
+                 quint64 total_size);
+    ~PostFileTask();
+
+protected:
+    void prepare();
+    void sendRequest();
+    void onHttpRequestFinished();
+
+private:
+    bool isChunked() const;
+    void setContentRangeHeader(QNetworkRequest *request);
+
+    const QString parent_dir_;
+    QFile *file_;
+    const QString name_;
+    const bool use_upload_;
+    const QString relative_path_;
+
+    quint64 total_size_;
+
+    quint64 start_offset_;
+    qint32 chunk_size_;
+    bool need_idx_progress_;
+};
+
+#endif // SEAFILE_CLIETN_FILEBROWSER_TAKS_H
diff --git a/src/filebrowser/seaf-dirent.cpp b/src/filebrowser/seaf-dirent.cpp
new file mode 100644 (file)
index 0000000..82305d9
--- /dev/null
@@ -0,0 +1,82 @@
+#include <jansson.h>
+#include <QDateTime>
+
+#include "utils/json-utils.h"
+
+#include "seaf-dirent.h"
+
+namespace {
+
+void initCommonFields(SeafDirent *dirent) {
+    dirent->mtime = QDateTime::currentDateTime().toTime_t();
+    dirent->readonly = false;
+    dirent->is_locked = false;
+    dirent->locked_by_me = false;
+}
+
+}
+
+SeafDirent SeafDirent::fromJSON(const json_t *root, json_error_t */* error */)
+{
+    SeafDirent dirent;
+    Json json(root);
+
+    dirent.id = json.getString("id");
+    dirent.name = json.getString("name");
+
+    QString type = json.getString("type");
+    if (type == "file") {
+        dirent.type = FILE;
+        dirent.size = json.getLong("size");
+    } else {
+        dirent.type = DIR;
+    }
+    dirent.readonly = json.getString("permission") == "r" ? true : false;
+    dirent.mtime = json.getLong("mtime");
+
+    dirent.is_locked = json.getBool("is_locked");
+    dirent.lock_owner = json.getString("lock_owner");
+    dirent.lock_owner_name = json.getString("lock_owner_name");
+    dirent.lock_time = json.getLong("lock_time");
+    dirent.locked_by_me = json.getBool("locked_by_me");
+    dirent.modifier_name = json.getString("modifier_name");
+
+    return dirent;
+}
+
+QList<SeafDirent> SeafDirent::listFromJSON(const json_t *json, json_error_t *error)
+{
+    QList<SeafDirent> dirents;
+    for (size_t i = 0; i < json_array_size(json); i++) {
+        SeafDirent dirent = fromJSON(json_array_get(json, i), error);
+        dirents.push_back(dirent);
+    }
+
+    return dirents;
+}
+
+const QString& SeafDirent::getLockOwnerDisplayString() const
+{
+    return !lock_owner_name.isEmpty() ? lock_owner_name : lock_owner;
+}
+
+SeafDirent SeafDirent::dir(const QString& name)
+{
+    SeafDirent dirent;
+    dirent.type = DIR;
+    dirent.name = name;
+
+    initCommonFields(&dirent);
+    return dirent;
+}
+
+SeafDirent SeafDirent::file(const QString& name, quint64 size)
+{
+    SeafDirent dirent;
+    dirent.type = FILE;
+    dirent.name = name;
+    dirent.size = size;
+
+    initCommonFields(&dirent);
+    return dirent;
+}
diff --git a/src/filebrowser/seaf-dirent.h b/src/filebrowser/seaf-dirent.h
new file mode 100644 (file)
index 0000000..8deca80
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef SEAFILE_CLIENT_API_SEAF_DIRENT_H
+#define SEAFILE_CLIENT_API_SEAF_DIRENT_H
+
+#include <jansson.h>
+
+#include <vector>
+#include <QString>
+#include <QList>
+#include <QMetaType>
+
+class SeafDirent {
+public:
+    enum Type {
+        DIR,
+        FILE
+    };
+    
+    Type type;
+    bool readonly;
+    QString id;
+    QString name;
+    quint64 size;
+    quint64 mtime;
+
+    bool is_locked;
+    bool locked_by_me;
+    QString lock_owner;
+    QString lock_owner_name;
+    quint64 lock_time;
+    QString modifier_name;
+
+    bool isDir() const { return type == DIR; }
+    bool isFile() const { return type == FILE; }
+
+    const QString& getLockOwnerDisplayString() const;
+
+    static SeafDirent fromJSON(const json_t*, json_error_t *error);
+    static QList<SeafDirent> listFromJSON(const json_t*, json_error_t *error);
+
+    static SeafDirent dir(const QString& name);
+    static SeafDirent file(const QString& name, quint64 size);
+};
+
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(SeafDirent)
+
+#endif // SEAFILE_CLIENT_API_SEAF_DIRENT_H
+
diff --git a/src/filebrowser/seafilelink-dialog.cpp b/src/filebrowser/seafilelink-dialog.cpp
new file mode 100644 (file)
index 0000000..bb5f626
--- /dev/null
@@ -0,0 +1,114 @@
+#include "seafilelink-dialog.h"
+
+#include <QtGlobal>
+#include <QtWidgets>
+#include "QtAwesome.h"
+#include "utils/utils.h"
+#include "utils/utils-mac.h"
+#include "open-local-helper.h"
+
+SeafileLinkDialog::SeafileLinkDialog(const QString& smart_link, QWidget *parent)
+    :web_link_(smart_link)
+{
+    setWindowTitle(tr("%1 Internal Link").arg(getBrand()));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->setSpacing(5);
+    layout->setContentsMargins(9, 9, 9, 9);
+
+    QString copy_to_str = tr("Copy to clipboard");
+    QIcon copy_to_icon = awesome->icon(icon_copy);
+
+    //
+    // create web link related
+    //
+    QLabel *web_label = new QLabel(tr("%1 Internal Link:").arg(getBrand()));
+    layout->addWidget(web_label);
+    QHBoxLayout *web_layout = new QHBoxLayout;
+
+    web_editor_ = new QLineEdit;
+    web_editor_->setText(web_link_);
+    web_editor_->selectAll();
+    web_editor_->setReadOnly(true);
+    web_editor_->setCursorPosition(0);
+
+    web_layout->addWidget(web_editor_);
+
+    QPushButton *web_copy_to = new QPushButton;
+    web_copy_to->setIcon(copy_to_icon);
+    web_copy_to->setToolTip(copy_to_str);
+    web_layout->addWidget(web_copy_to);
+    connect(web_copy_to, SIGNAL(clicked()), this, SLOT(onCopyWebText()));
+    layout->addLayout(web_layout);
+
+    //
+    // create seafile-protocol link related
+    //
+//    QLabel *protocol_label = new QLabel(tr("%1 Protocol Link:").arg(getBrand()));
+//    layout->addWidget(protocol_label);
+//    QHBoxLayout *protocol_layout = new QHBoxLayout;
+
+//    protocol_editor_ = new QLineEdit;
+//    protocol_editor_->setText(protocol_link_);
+//    protocol_editor_->selectAll();
+//    protocol_editor_->setReadOnly(true);
+//    protocol_editor_->setCursorPosition(0);
+
+//    protocol_layout->addWidget(protocol_editor_);
+
+//    QPushButton *protocol_copy_to = new QPushButton;
+//    protocol_copy_to->setIcon(copy_to_icon);
+//    protocol_copy_to->setToolTip(copy_to_str);
+//    protocol_layout->addWidget(protocol_copy_to);
+//    connect(protocol_copy_to, SIGNAL(clicked()), this, SLOT(onCopyProtocolText()));
+//    layout->addLayout(protocol_layout);
+
+    QHBoxLayout *hlayout = new QHBoxLayout;
+
+    QWidget *spacer = new QWidget;
+    spacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+    hlayout->addWidget(spacer);
+
+    QWidget *spacer2 = new QWidget;
+    spacer2->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+    hlayout->addWidget(spacer2);
+
+    QWidget *spacer3 = new QWidget;
+    spacer3->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+    hlayout->addWidget(spacer3);
+
+    QPushButton *ok = new QPushButton(tr("OK"));
+    hlayout->addWidget(ok);
+    connect(ok, SIGNAL(clicked()), this, SLOT(accept()));
+    ok->setFocus();
+
+    layout->addLayout(hlayout);
+
+    setLayout(layout);
+
+    setMinimumWidth(450);
+}
+
+void SeafileLinkDialog::onCopyWebText()
+{
+// for mac, qt copys many minedatas beside public.utf8-plain-text
+// e.g. public.vcard, which we don't want to use
+#ifndef Q_OS_MAC
+    QApplication::clipboard()->setText(web_link_);
+#else
+    utils::mac::copyTextToPasteboard(web_link_);
+#endif
+}
+
+void SeafileLinkDialog::onCopyProtocolText()
+{
+// for mac, qt copys many minedatas beside public.utf8-plain-text
+// e.g. public.vcard, which we don't want to use
+#ifndef Q_OS_MAC
+    QApplication::clipboard()->setText(protocol_link_);
+#else
+    utils::mac::copyTextToPasteboard(protocol_link_);
+#endif
+}
diff --git a/src/filebrowser/seafilelink-dialog.h b/src/filebrowser/seafilelink-dialog.h
new file mode 100644 (file)
index 0000000..9328ee4
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_SEAFILELINK_DIALOG_H
+#define SEAFILE_CLIENT_FILE_BROWSER_SEAFILELINK_DIALOG_H
+#include <QDialog>
+
+class QLineEdit;
+class Account;
+class SeafileLinkDialog : public QDialog
+{
+    Q_OBJECT
+public:
+    SeafileLinkDialog(const QString& smart_link, QWidget *parent = NULL);
+
+private slots:
+    void onCopyWebText();
+    void onCopyProtocolText();
+
+private:
+    QString web_link_;
+    const QString protocol_link_;
+    QLineEdit *web_editor_;
+    QLineEdit *protocol_editor_;
+};
+
+#endif
diff --git a/src/filebrowser/sharedlink-dialog.cpp b/src/filebrowser/sharedlink-dialog.cpp
new file mode 100644 (file)
index 0000000..1239440
--- /dev/null
@@ -0,0 +1,74 @@
+#include "sharedlink-dialog.h"
+
+#include <QtGlobal>
+#include <QtWidgets>
+#include "utils/utils-mac.h"
+
+SharedLinkDialog::SharedLinkDialog(const QString &text, QWidget *parent)
+  : text_(text)
+{
+    setWindowTitle(tr("Share Link"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    QVBoxLayout *layout = new QVBoxLayout;
+
+    QLabel *label = new QLabel(tr("Share link:"));
+    layout->addWidget(label);
+    layout->setSpacing(5);
+    layout->setContentsMargins(9, 9, 9, 9);
+
+    editor_ = new QLineEdit;
+    editor_->setText(text_);
+    editor_->selectAll();
+    editor_->setReadOnly(true);
+    layout->addWidget(editor_);
+
+    QHBoxLayout *hlayout = new QHBoxLayout;
+
+    QCheckBox *is_download_checked = new QCheckBox(tr("Direct Download"));
+    connect(is_download_checked, SIGNAL(stateChanged(int)),
+            this, SLOT(onDownloadStateChanged(int)));
+    hlayout->addWidget(is_download_checked);
+
+    QWidget *spacer = new QWidget;
+    spacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+    hlayout->addWidget(spacer);
+
+    QWidget *spacer2 = new QWidget;
+    spacer2->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+    hlayout->addWidget(spacer2);
+
+    QPushButton *copy_to = new QPushButton(tr("Copy to clipboard"));
+    hlayout->addWidget(copy_to);
+    connect(copy_to, SIGNAL(clicked()), this, SLOT(onCopyText()));
+
+    QPushButton *ok = new QPushButton(tr("OK"));
+    hlayout->addWidget(ok);
+    connect(ok, SIGNAL(clicked()), this, SLOT(accept()));
+
+    layout->addLayout(hlayout);
+
+    setLayout(layout);
+
+    setMinimumWidth(300);
+    setMaximumWidth(400);
+}
+
+void SharedLinkDialog::onCopyText()
+{
+// for mac, qt copys many minedatas beside public.utf8-plain-text
+// e.g. public.vcard, which we don't want to use
+#ifndef Q_OS_MAC
+    QApplication::clipboard()->setText(editor_->text());
+#else
+    utils::mac::copyTextToPasteboard(editor_->text());
+#endif
+}
+
+void SharedLinkDialog::onDownloadStateChanged(int state)
+{
+    if (state == Qt::Checked)
+        editor_->setText(text_ + "?dl=1");
+    else
+        editor_->setText(text_);
+}
diff --git a/src/filebrowser/sharedlink-dialog.h b/src/filebrowser/sharedlink-dialog.h
new file mode 100644 (file)
index 0000000..822f98f
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_SHAREDLINK_DIALOG_H
+#define SEAFILE_CLIENT_FILE_BROWSER_SHAREDLINK_DIALOG_H
+#include <QDialog>
+
+class QLineEdit;
+class SharedLinkDialog : public QDialog
+{
+    Q_OBJECT
+public:
+    SharedLinkDialog(const QString &text, QWidget *parent);
+
+private slots:
+    void onCopyText();
+    void onDownloadStateChanged(int state);
+private:
+    const QString text_;
+    QLineEdit *editor_;
+};
+
+#endif
diff --git a/src/filebrowser/tasks.cpp b/src/filebrowser/tasks.cpp
new file mode 100644 (file)
index 0000000..1737ffb
--- /dev/null
@@ -0,0 +1,869 @@
+#include <QThread>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QHttpMultiPart>
+#include <QHttpPart>
+#include <QFile>
+#include <QFileInfo>
+#include <QTemporaryFile>
+#include <QSslError>
+#include <QSslConfiguration>
+#include <QSslCertificate>
+#include <QDirIterator>
+#include <QTimer>
+#include <QApplication>
+#include <QMutexLocker>
+#include <QNetworkConfigurationManager>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "certs-mgr.h"
+#include "api/api-error.h"
+#include "configurator.h"
+#include "network-mgr.h"
+#include "reliable-upload.h"
+#include "tasks.h"
+
+namespace {
+
+const char *kFileDownloadTmpDirName = "fcachetmp";
+
+const int kMaxRedirects = 3;
+const int kFileServerTaskMaxRetry = 3;
+const int kFileServerTaskRetryIntervalSecs = 10;
+
+class QNAMWrapper {
+public:
+    QNAMWrapper() {
+        should_reset_qnam_ = false;
+        network_mgr_ = nullptr;
+    }
+
+    QNetworkAccessManager *getQNAM() {
+        QMutexLocker lock(&network_mgr_lock_);
+
+        if (!network_mgr_) {
+            network_mgr_ = createQNAM();
+        } else if (should_reset_qnam_) {
+            network_mgr_->deleteLater();
+            network_mgr_ = createQNAM();
+            should_reset_qnam_ = false;
+        }
+        return network_mgr_;
+    }
+
+    QNetworkAccessManager *createQNAM() {
+        QNetworkAccessManager *manager = new QNetworkAccessManager;
+        NetworkManager::instance()->addWatch(manager);
+        manager->setConfiguration(
+            QNetworkConfigurationManager().defaultConfiguration());
+        return manager;
+    }
+
+    void resetQNAM() {
+        QMutexLocker lock(&network_mgr_lock_);
+        should_reset_qnam_ = true;
+    }
+
+private:
+    QNetworkAccessManager* network_mgr_;
+    QMutex network_mgr_lock_;
+    bool should_reset_qnam_;
+};
+
+QNAMWrapper* qnam_wrapper_ = new QNAMWrapper();
+
+} // namesapce
+
+QThread* FileNetworkTask::worker_thread_;
+
+FileNetworkTask::FileNetworkTask(const Account& account,
+                                 const QString& repo_id,
+                                 const QString& path,
+                                 const QString& local_path)
+    : account_(account),
+      repo_id_(repo_id),
+      path_(path),
+      local_path_(local_path),
+      canceled_(false),
+      progress_(0, 0)
+{
+    fileserver_task_ = NULL;
+    get_link_req_ = NULL;
+    http_error_code_ = 0;
+    auto_delete_ = true;
+}
+
+FileNetworkTask::~FileNetworkTask()
+{
+    // printf ("destructor called for FileNetworkTask\n");
+    if (get_link_req_) {
+        get_link_req_->deleteLater();
+        get_link_req_ = nullptr;
+    }
+    if (fileserver_task_) {
+        fileserver_task_->deleteLater();
+        fileserver_task_ = nullptr;
+    }
+}
+
+QString FileNetworkTask::fileName() const
+{
+    return QFileInfo(path_).fileName();
+}
+
+void FileNetworkTask::start()
+{
+    createGetLinkRequest();
+    connect(get_link_req_, SIGNAL(success(const QString&)),
+            this, SLOT(onLinkGet(const QString&)));
+    connect(get_link_req_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetLinkFailed(const ApiError&)));
+    get_link_req_->send();
+}
+
+void FileNetworkTask::onFileServerTaskProgressUpdate(qint64 transferred, qint64 total)
+{
+    progress_.transferred = transferred;
+    progress_.total = total;
+    emit progressUpdate(transferred, total);
+}
+
+void FileNetworkTask::onFileServerTaskNameUpdate(QString current_name)
+{
+    emit nameUpdate(current_name);
+}
+
+void FileNetworkTask::onLinkGet(const QString& link)
+{
+    startFileServerTask(link);
+}
+
+void FileNetworkTask::startFileServerTask(const QString& link)
+{
+    createFileServerTask(link);
+
+    connect(fileserver_task_, SIGNAL(progressUpdate(qint64, qint64)),
+            this, SLOT(onFileServerTaskProgressUpdate(qint64, qint64)));
+    connect(fileserver_task_, SIGNAL(nameUpdate(QString)),
+            this, SLOT(onFileServerTaskNameUpdate(QString)));
+    connect(fileserver_task_, SIGNAL(finished(bool)),
+            this, SLOT(onFileServerTaskFinished(bool)));
+    connect(fileserver_task_, SIGNAL(retried(int)),
+            this, SIGNAL(retried(int)));
+
+    if (!worker_thread_) {
+        worker_thread_ = new QThread;
+        worker_thread_->start();
+    }
+
+    if (type() == Download) {
+        // From now on the this task would run in the worker thread
+        fileserver_task_->moveToThread(worker_thread_);
+        QMetaObject::invokeMethod(fileserver_task_, "start");
+    } else {
+        // ReliablePostFileTask is a bit complicated and it would manage the
+        // thread-affinity itself.
+        fileserver_task_->start();
+    }
+}
+
+void FileNetworkTask::cancel()
+{
+    canceled_ = true;
+    if (get_link_req_) {
+        get_link_req_->deleteLater();
+        get_link_req_ = 0;
+    }
+    if (fileserver_task_) {
+        QMetaObject::invokeMethod(fileserver_task_, "cancel");
+    }
+    error_ = TaskCanceled;
+    error_string_ = tr("Operation canceled");
+    onFinished(false);
+}
+
+void FileNetworkTask::onFileServerTaskFinished(bool success)
+{
+    if (canceled_) {
+        return;
+    }
+    if (!fileserver_task_->canceled() && !success) {
+        error_ = fileserver_task_->error();
+        error_string_ = fileserver_task_->errorString();
+        http_error_code_ = fileserver_task_->httpErrorCode();
+        failed_path_ = fileserver_task_->failedPath();
+    }
+    oid_ = fileserver_task_->oid();
+    url_ = fileserver_task_->url();
+    onFinished(success);
+}
+
+void FileNetworkTask::onFinished(bool success)
+{
+    emit finished(success);
+    if (auto_delete_) {
+        deleteLater();
+    }
+}
+
+void FileNetworkTask::onGetLinkFailed(const ApiError& error)
+{
+    error_ = ApiRequestError;
+    error_string_ = error.toString();
+    if (error.type() == ApiError::HTTP_ERROR) {
+        http_error_code_ = error.httpErrorCode();
+    }
+    onFinished(false);
+}
+
+FileNetworkTask::Progress::Progress(qint64 transferred, qint64 total)
+{
+    this->transferred = transferred;
+    this->total = total;
+}
+
+QString FileNetworkTask::Progress::toString() const
+{
+    if (total > 0) {
+        return QString::number(100 * transferred / total) + "%";
+    }
+    return tr("pending");
+}
+
+FileDownloadTask::FileDownloadTask(const Account& account,
+                                   const QString& repo_id,
+                                   const QString& path,
+                                   const QString& local_path,
+                                   bool is_save_as_task)
+    : FileNetworkTask(account, repo_id, path, local_path), is_save_as_task_(is_save_as_task)
+{
+}
+
+void FileDownloadTask::createGetLinkRequest()
+{
+    if (get_link_req_) {
+        get_link_req_->deleteLater();
+    }
+    get_link_req_ = new GetFileDownloadLinkRequest(account_, repo_id_, path_);
+}
+
+void FileDownloadTask::onLinkGet(const QString& link)
+{
+    GetFileDownloadLinkRequest *req = (GetFileDownloadLinkRequest *)get_link_req_;
+    file_id_ = req->fileId();
+    FileNetworkTask::onLinkGet(link);
+}
+
+void FileDownloadTask::createFileServerTask(const QString& link)
+{
+    fileserver_task_ = new GetFileTask(link, local_path_);
+}
+
+FileUploadTask::FileUploadTask(const Account& account,
+                               const QString& repo_id,
+                               const QString& path,
+                               const QString& local_path,
+                               const QString& name,
+                               const bool use_upload,
+                               const bool accept_user_confirmation)
+    : FileNetworkTask(account, repo_id, path, local_path),
+      name_(name),
+      use_upload_(use_upload),
+      accept_user_confirmation_(accept_user_confirmation)
+{
+}
+
+FileUploadTask::FileUploadTask(const FileUploadTask& rhs)
+    : FileNetworkTask(rhs.account_, rhs.repo_id_, rhs.path_, rhs.local_path_),
+      name_(rhs.name_),
+      use_upload_(rhs.use_upload_),
+      accept_user_confirmation_(rhs.accept_user_confirmation_)
+{
+}
+
+void FileUploadTask::createGetLinkRequest()
+{
+    get_link_req_ = new GetFileUploadLinkRequest(account_, repo_id_, path_, use_upload_);
+}
+
+void FileUploadTask::createFileServerTask(const QString& link)
+{
+    fileserver_task_ = new ReliablePostFileTask(account_, repo_id_, link, path_, local_path_,
+                                                name_, use_upload_, accept_user_confirmation_);
+}
+
+void FileUploadTask::startFileServerTask(const QString& link)
+{
+    FileNetworkTask::startFileServerTask(link);
+    connect(fileserver_task_, SIGNAL(oneFileFailed(const QString&, bool)),
+            this, SLOT(onOneFileFailed(const QString&, bool)));
+}
+
+void FileUploadTask::onOneFileFailed(const QString& filename, bool single_file)
+{
+    emit oneFileFailed(filename, single_file);
+}
+
+void FileUploadTask::continueWithFailedFile(bool retry)
+{
+    retry_ = retry;
+    createGetLinkRequest();
+    connect(get_link_req_, SIGNAL(success(const QString&)),
+            this, SLOT(onLinkGetAgain(const QString&)));
+    connect(get_link_req_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetLinkFailed(const ApiError&)));
+    get_link_req_->send();
+}
+
+void FileUploadTask::onLinkGetAgain(const QString& link)
+{
+    fileserver_task_->continueWithFailedFile(retry_, link);
+}
+
+FileUploadMultipleTask::FileUploadMultipleTask(const Account& account,
+                                               const QString& repo_id,
+                                               const QString& path,
+                                               const QString& local_path,
+                                               const QStringList& names,
+                                               bool use_upload)
+  : FileUploadTask(account, repo_id, path, local_path, QString(), use_upload),
+  names_(names)
+{
+}
+
+void FileUploadMultipleTask::createFileServerTask(const QString& link)
+{
+    fileserver_task_ = new PostFilesTask(link, path_, local_path_, names_, false);
+}
+
+const QStringList& FileUploadMultipleTask::successfulNames()
+{
+    return ((PostFilesTask *)fileserver_task_)->successfulNames();
+}
+
+
+FileUploadDirectoryTask::FileUploadDirectoryTask(const Account& account,
+                                                 const QString& repo_id,
+                                                 const QString& path,
+                                                 const QString& local_path,
+                                                 const QString& name)
+  : FileUploadTask(account, repo_id, path, local_path, name)
+{
+}
+
+void FileUploadDirectoryTask::createFileServerTask(const QString& link)
+{
+    QStringList names;
+
+    if (local_path_ == "/")
+        qWarning("attempt to upload the root directory, you should avoid it\n");
+    QDir dir(local_path_);
+
+    QDirIterator iterator(dir.absolutePath(), QDirIterator::Subdirectories);
+    // XXX (lins05): Move these operations into a thread
+    while (iterator.hasNext()) {
+        iterator.next();
+        QString file_path = iterator.filePath();
+        QString relative_path = dir.relativeFilePath(file_path);
+        QString base_name = ::getBaseName(file_path);
+        if (base_name == "." || base_name == "..") {
+            continue;
+        }
+        if (!iterator.fileInfo().isDir()) {
+            names.push_back(relative_path);
+        } else {
+            if (account_.isAtLeastVersion(4, 4, 0)) {
+                // printf("a folder: %s\n", file_path.toUtf8().data());
+                if (QDir(file_path).entryList().length() == 2) {
+                    // only contains . and .., so an empty folder
+                    // printf("an empty folder: %s\n", file_path.toUtf8().data());
+                    empty_subfolders_.append(::pathJoin(::getBaseName(local_path_), relative_path));
+                }
+            }
+        }
+    }
+
+    if (names.isEmpty() && empty_subfolders_.isEmpty()) {
+        // The folder dragged into cloud file browser is an empty one. We use
+        // the special name "." to represent it.
+        empty_subfolders_.append(".");
+    }
+
+    // printf("total empty folders: %d for %s\n", empty_subfolders_.length(), dir.absolutePath().toUtf8().data());
+    fileserver_task_ = new PostFilesTask(link, path_, dir.absolutePath(), names, true);
+}
+
+void FileUploadDirectoryTask::onFinished(bool success)
+{
+    if (!success || (empty_subfolders_.empty())) {
+        FileUploadTask::onFinished(success);
+        return;
+    }
+
+    nextEmptyFolder();
+}
+
+void FileUploadDirectoryTask::nextEmptyFolder()
+{
+    if (empty_subfolders_.isEmpty()) {
+        FileUploadDirectoryTask::onFinished(true);
+        return;
+    }
+
+    QString folder = empty_subfolders_.takeFirst();
+
+    bool create_parents = true;
+    if (folder == ".") {
+        // This is the case of an empty top-level folder.
+        create_parents = false;
+        folder = ::getBaseName(local_path_);
+    }
+
+    create_dir_req_.reset(new CreateDirectoryRequest(
+                                account_, repo_id_, ::pathJoin(path_, folder), create_parents));
+
+    connect(create_dir_req_.data(), SIGNAL(success(const QString&)),
+            this, SLOT(nextEmptyFolder()));
+    connect(create_dir_req_.data(), SIGNAL(failed(const ApiError&)),
+            this, SLOT(onCreateDirFailed(const ApiError&)));
+    create_dir_req_->send();
+}
+
+void FileUploadDirectoryTask::onCreateDirFailed(const ApiError &error)
+{
+    error_ = ApiRequestError;
+    error_string_ = error.toString();
+    http_error_code_ = error.httpErrorCode();
+    FileUploadDirectoryTask::onFinished(false);
+}
+
+FileServerTask::FileServerTask(const QUrl& url, const QString& local_path)
+    : url_(url),
+      local_path_(local_path),
+      reply_(nullptr),
+      canceled_(false),
+      redirect_count_(0),
+      retry_count_(0),
+      http_error_code_(0)
+{
+}
+
+FileServerTask::~FileServerTask()
+{
+}
+
+void FileServerTask::resetQNAM()
+{
+    qnam_wrapper_->resetQNAM();
+}
+
+QNetworkAccessManager *FileServerTask::getQNAM()
+{
+    QNetworkAccessManager *qnam = qnam_wrapper_->getQNAM();
+    connect(qnam, SIGNAL(destroyed(QObject *)), this, SLOT(doAbort()));
+    return qnam;
+}
+
+void FileServerTask::doAbort()
+{
+    if (reply_ && reply_->isRunning()) {
+        qWarning("aborting FileServerTask %s on network error", toCStr(reply_->url().toString()));
+        reply_->abort();
+    }
+}
+
+void FileServerTask::onSslErrors(const QList<QSslError>& errors)
+{
+    if (canceled_) {
+        return;
+    }
+    QUrl url = reply_->url();
+    QSslCertificate cert = reply_->sslConfiguration().peerCertificate();
+    CertsManager *mgr = seafApplet->certsManager();
+    if (!cert.isNull() && cert == mgr->getCertificate(url.toString())) {
+        reply_->ignoreSslErrors();
+        return;
+    }
+}
+
+void FileServerTask::start()
+{
+    prepare();
+    sendRequest();
+}
+
+void FileServerTask::cancel()
+{
+    canceled_ = true;
+    if (reply_) {
+        reply_->abort();
+    }
+}
+
+bool FileServerTask::retryEnabled()
+{
+    return false;
+}
+
+void FileServerTask::retry()
+{
+    if (canceled_) {
+        qWarning("[file server task] stop retrying because task is cancelled\n");
+        return;
+    }
+    qDebug("[file server task] now retry the file server task for the %d time\n", retry_count_);
+    emit retried(retry_count_);
+    start();
+}
+
+bool FileServerTask::maybeRetry()
+{
+    if (canceled_ || !retryEnabled()) {
+        return false;
+    }
+    if (retry_count_ >= kFileServerTaskMaxRetry) {
+        return false;
+    } else {
+        retry_count_++;
+        qDebug("[file server task] schedule file server task retry for the %d time\n", retry_count_);
+        QTimer::singleShot(kFileServerTaskRetryIntervalSecs * 1000, this, SLOT(retry()));
+        return true;
+    }
+}
+
+void FileServerTask::httpRequestFinished()
+{
+    if (canceled_) {
+        setError(FileNetworkTask::TaskCanceled, tr("task cancelled"));
+        emit finished(false);
+        return;
+    }
+
+    int code = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+    if (code == 0 && reply_->error() != QNetworkReply::NoError) {
+
+        NetworkStatusDetector::instance()->setNetworkFailure(reply_->error());
+
+        qWarning("[file server task] network error: %s\n", toCStr(reply_->errorString()));
+        if (!maybeRetry()) {
+            setError(FileNetworkTask::ApiRequestError, reply_->errorString());
+            emit finished(false);
+            return;
+        }
+        return;
+    }
+
+    if (handleHttpRedirect()) {
+        return;
+    }
+
+    if ((code / 100) == 4 || (code / 100) == 5) {
+        qWarning("request failed for %s: status code %d\n",
+               toCStr(reply_->url().toString()), code);
+        // Response code 400 means the link may have already expired.
+        if (code == 400 || !maybeRetry()) {
+            setHttpError(code);
+            emit finished(false);
+            return;
+        }
+        return;
+    }
+
+    onHttpRequestFinished();
+}
+
+bool FileServerTask::handleHttpRedirect()
+{
+    QVariant redirect_attr = reply_->attribute(QNetworkRequest::RedirectionTargetAttribute);
+    if (redirect_attr.isNull()) {
+        return false;
+    }
+
+    if (redirect_count_++ > kMaxRedirects) {
+        // simply treat too many redirects as server side error
+        setHttpError(500);
+        emit finished(false);
+        qWarning("too many redirects for %s\n",
+               toCStr(reply_->url().toString()));
+        return true;
+    }
+
+    url_ = redirect_attr.toUrl();
+    if (url_.isRelative()) {
+        url_ = reply_->url().resolved(url_);
+    }
+    qWarning("redirect to %s (from %s)\n", toCStr(url_.toString()),
+           toCStr(reply_->url().toString()));
+    reply_->deleteLater();
+    sendRequest();
+    return true;
+}
+
+
+GetFileTask::GetFileTask(const QUrl& url, const QString& local_path)
+    : FileServerTask(url, local_path),
+      tmp_file_(NULL)
+{
+}
+
+GetFileTask::~GetFileTask()
+{
+    if (tmp_file_) {
+        tmp_file_->remove();
+        delete tmp_file_;
+    }
+}
+
+void GetFileTask::prepare()
+{
+    QString download_tmp_dir = ::pathJoin(
+        seafApplet->configurator()->seafileDir(), kFileDownloadTmpDirName);
+    if (!::createDirIfNotExists(download_tmp_dir)) {
+        setError(FileNetworkTask::FileIOError, tr("Failed to create folders"));
+        emit finished(false);
+        return;
+    }
+
+    QString tmpf_path = ::pathJoin(download_tmp_dir, "seaf-XXXXXX");
+    tmp_file_ = new QTemporaryFile(tmpf_path);
+    tmp_file_->setAutoRemove(false);
+    if (!tmp_file_->open()) {
+        setError(FileNetworkTask::FileIOError, tr("Failed to create temporary files"));
+        emit finished(false);
+    }
+}
+
+void GetFileTask::sendRequest()
+{
+    QNetworkRequest request(url_);
+    reply_ = getQNAM()->get(request);
+
+    connect(reply_, SIGNAL(sslErrors(const QList<QSslError>&)),
+            this, SLOT(onSslErrors(const QList<QSslError>&)));
+
+    connect(reply_, SIGNAL(readyRead()), this, SLOT(httpReadyRead()));
+    connect(reply_, SIGNAL(downloadProgress(qint64, qint64)),
+            this, SIGNAL(progressUpdate(qint64, qint64)));
+    connect(reply_, SIGNAL(finished()), this, SLOT(httpRequestFinished()));
+}
+
+void GetFileTask::httpReadyRead()
+{
+    if (canceled_) {
+        return;
+    }
+    // TODO: read in blocks (e.g 64k) instead of readAll
+    // TODO: check http status code
+    QByteArray chunk = reply_->readAll();
+    if (!chunk.isEmpty()) {
+        if (tmp_file_->write(chunk) <= 0) {
+            setError(FileNetworkTask::FileIOError, tr("Failed to create folders"));
+            emit finished(false);
+        }
+    }
+}
+
+void GetFileTask::onHttpRequestFinished()
+{
+    if (canceled_) {
+        return;
+    }
+    tmp_file_->close();
+
+    QString parent_dir = ::getParentPath(local_path_);
+    if (!::createDirIfNotExists(parent_dir)) {
+        setError(FileNetworkTask::FileIOError, tr("Failed to write file to disk"));
+        emit finished(false);
+    }
+
+    QFile oldfile(local_path_);
+    if (oldfile.exists() && !oldfile.remove()) {
+        setError(FileNetworkTask::FileIOError, tr("Failed to remove the older version of the downloaded file"));
+        emit finished(false);
+        return;
+    }
+
+    if (!tmp_file_->rename(local_path_)) {
+        setError(FileNetworkTask::FileIOError, tr("Failed to move file"));
+        emit finished(false);
+        return;
+    }
+
+    delete tmp_file_;
+    tmp_file_ = 0;
+    emit finished(true);
+}
+
+PostFilesTask::PostFilesTask(const QUrl& url,
+                             const QString& parent_dir,
+                             const QString& local_path,
+                             const QStringList& names,
+                             const bool use_relative)
+    : FileServerTask(url, local_path),
+      // work around with server
+      parent_dir_(parent_dir.endsWith('/') ? parent_dir : parent_dir + "/"),
+      name_(QFileInfo(local_path_).fileName()),
+      names_(names),
+      current_num_(-1),
+      progress_update_timer_(new QTimer(this)),
+      use_relative_(use_relative)
+{
+    // never used, set it to NULL to avoid segment fault
+    reply_ = NULL;
+    connect(progress_update_timer_, SIGNAL(timeout()), this, SLOT(onProgressUpdate()));
+}
+
+PostFilesTask::~PostFilesTask()
+{
+}
+
+void PostFilesTask::prepare()
+{
+    current_bytes_ = 0;
+    transferred_bytes_ = 0;
+    total_bytes_ = 0;
+
+    file_sizes_.reserve(names_.size());
+    Q_FOREACH(const QString &name, names_)
+    {
+        QString local_path = ::pathJoin(local_path_, name);
+        // approximate the bytes used by http protocol (e.g. the bytes of
+        // header)
+        qint64 file_size = QFileInfo(local_path).size() + 1024;
+        file_sizes_.push_back(file_size);
+        total_bytes_ += file_size;
+    }
+}
+
+void PostFilesTask::cancel()
+{
+    if (canceled_) {
+        return;
+    }
+    progress_update_timer_->stop();
+    canceled_ = true;
+    task_->cancel();
+}
+
+void PostFilesTask::sendRequest()
+{
+    startNext();
+}
+
+void PostFilesTask::onProgressUpdate()
+{
+    emit progressUpdate(current_bytes_ + transferred_bytes_, total_bytes_);
+}
+
+void PostFilesTask::onPostTaskProgressUpdate(qint64 bytes, qint64 /* sum_bytes */)
+{
+    current_bytes_ = bytes;
+}
+
+void PostFilesTask::onPostTaskFinished(bool success)
+{
+    if (canceled_) {
+        return;
+    }
+
+    if (!success) {
+        error_ = task_->error();
+        error_string_ = task_->errorString();
+        http_error_code_ = task_->httpErrorCode();
+        progress_update_timer_->stop();
+
+        const QString& file_path = names_[current_num_];
+        QString file_name = QFileInfo(file_path).fileName();
+        failed_path_ = file_name;
+
+        emit oneFileFailed(failed_path_, false);
+        return;
+    } else {
+        error_ = FileNetworkTask::NoError;
+        error_string_ = "";
+        http_error_code_ = 0;
+        progress_update_timer_->stop();
+        successful_names_ << names_[current_num_];
+    }
+
+    transferred_bytes_ += file_sizes_[current_num_];
+    startNext();
+}
+
+void PostFilesTask::startNext(const QString& link)
+{
+    progress_update_timer_->stop();
+    if (++current_num_ == names_.size()) {
+        emit finished(true);
+        return;
+    }
+    const QString& file_path = names_[current_num_];
+    QString file_name = QFileInfo(file_path).fileName();
+    current_name_ = file_name;
+    emit nameUpdate(current_name_);
+    QString relative_path;
+    if (use_relative_)
+        relative_path = ::pathJoin(QFileInfo(local_path_).fileName(), ::getParentPath(file_path));
+
+    // relative_path might be empty, and should be safe to use as well
+    if (!link.isEmpty()) {
+        url_ = link;
+    }
+    task_.reset(new ReliablePostFileTask(url_,
+        parent_dir_,
+        ::pathJoin(local_path_, file_path),
+        file_name,
+        relative_path));
+    connect(task_.data(), SIGNAL(progressUpdate(qint64, qint64)),
+            this, SLOT(onPostTaskProgressUpdate(qint64, qint64)));
+    connect(task_.data(), SIGNAL(finished(bool)),
+            this, SLOT(onPostTaskFinished(bool)));
+    current_bytes_ = 0;
+    progress_update_timer_->start(100);
+    task_->start();
+}
+
+void PostFilesTask::continueWithFailedFile(bool retry, const QString& link)
+{
+    if (retry) {
+        current_num_--;
+    } else {
+        // The user chooses to skip the failed file, but in order to keep the
+        // progress consistent, we need to pretend the file is already uploaded
+        // successfully.
+        transferred_bytes_ += file_sizes_[current_num_];
+    }
+    startNext(link);
+}
+
+void FileServerTask::setError(FileNetworkTask::TaskError error,
+                              const QString& error_string)
+{
+    qWarning("[file server task] error: %s\n", toCStr(error_string));
+    error_ = error;
+    error_string_ = error_string;
+}
+
+void FileServerTask::setHttpError(int code)
+{
+    error_ = FileNetworkTask::ApiRequestError;
+    http_error_code_ = code;
+    if (code == 500) {
+        error_string_ = tr("Internal Server Error");
+    } else if (code == 443 || code == 520) {
+        // Handle the case when the storage quote is exceeded. It may happen in two cases:
+        //
+        // First, the quota has been used up before the upload. In such case
+        // seahub would return 520 to the generate-link request.
+        // See https://github.com/haiwen/seahub/blob/v6.0.7-server/seahub/api2/views.py#L133
+        //
+        // Second, the quota is not exceeded before the upload, but would exceed
+        // after the upload. In such case httpserver would return 443 to the
+        // multipart upload request.
+        // See https://github.com/haiwen/seafile-server/blob/v6.0.7-server/server/http-status-codes.h#L10
+        error_string_ = tr("The storage quota has been used up");
+    }
+}
diff --git a/src/filebrowser/tasks.h b/src/filebrowser/tasks.h
new file mode 100644 (file)
index 0000000..e6484cb
--- /dev/null
@@ -0,0 +1,440 @@
+#ifndef SEAFILE_CLIETN_FILEBROWSER_TAKS_H
+#define SEAFILE_CLIETN_FILEBROWSER_TAKS_H
+
+#include <QObject>
+#include <QUrl>
+#include <QMutex>
+
+#include "api/server-repo.h"
+#include "account.h"
+#include "file-browser-requests.h"
+
+class QTemporaryFile;
+class QFile;
+class QNetworkAccessManager;
+class QNetworkReply;
+class QThread;
+class QSslError;
+class QNetworkRequest;
+
+class FileServerTask;
+class ApiError;
+
+class ReliablePostFileTask;
+
+template<typename T> class QList;
+
+// deleter
+template<typename T>
+struct doDeleteLater
+{
+    static inline void cleanup(T *pointer) {
+        if (pointer != NULL)
+            pointer->deleteLater();
+    }
+};
+
+/**
+ * Handles file upload/download using seafile web api.
+ * The task contains two phases:
+ *
+ * First, we need to get the upload/download link for seahub.
+ * Second, we upload/download file to seafile fileserver with that link using
+ * a `FileServerTask`.
+ *
+ *
+ * In second phase, the FileServerTask is moved to a worker thread to execute,
+ * since we will do blocking file IO in that task.
+ *
+ * @abstract
+ */
+class FileNetworkTask: public QObject {
+    Q_OBJECT
+    friend class ReliablePostFileTask;
+public:
+    enum TaskType {
+        Upload,
+        Download
+    };
+
+    class Progress {
+    public:
+        Progress(qint64 transferred, qint64 total);
+        QString toString() const;
+        qint64 transferred, total;
+    };
+
+    FileNetworkTask(const Account& account,
+                    const QString& repo_id,
+                    const QString& path,
+                    const QString& local_path);
+
+    virtual ~FileNetworkTask();
+
+    void setAutoDelete(bool auto_delete) { auto_delete_ = auto_delete; }
+
+    // accessors
+    virtual TaskType type() const = 0;
+    const QString& repoId() const { return repo_id_; };
+    const Account& account() const { return account_; };
+    QString path() const { return path_; };
+    QString localFilePath() const { return local_path_; }
+    QString failedPath() const { return failed_path_; }
+    QString fileName() const;
+    QString oid() const { return oid_; }
+    QUrl url() const { return url_; }
+    Progress progress() const { return progress_; };
+    bool canceled() const { return canceled_; }
+    bool autoDelete() const { return auto_delete_; }
+
+    enum TaskError {
+        NoError = 0,
+        ApiRequestError,
+        FileIOError,
+        TaskCanceled
+    };
+    const TaskError& error() const { return error_; }
+    const QString& errorString() const { return error_string_; }
+    int httpErrorCode() const { return http_error_code_; }
+
+public slots:
+    virtual void start();
+    virtual void cancel();
+
+signals:
+    void progressUpdate(qint64 transferred, qint64 total);
+    void nameUpdate(QString current_name);
+    void finished(bool success);
+    void retried(int retry_count);
+
+protected slots:
+    void onFileServerTaskProgressUpdate(qint64 transferred, qint64 total);
+    void onFileServerTaskNameUpdate(QString current_name);
+    virtual void onLinkGet(const QString& link);
+    virtual void onGetLinkFailed(const ApiError& error);
+    virtual void startFileServerTask(const QString& link);
+    virtual void onFileServerTaskFinished(bool success);
+    virtual void onFinished(bool success);
+
+protected:
+    virtual void createGetLinkRequest() = 0;
+    virtual void createFileServerTask(const QString& link) = 0;
+
+    FileServerTask *fileserver_task_;
+    SeafileApiRequest *get_link_req_;
+
+    const Account account_;
+    const QString repo_id_;
+    QString path_;
+    QString local_path_;
+    QString failed_path_;
+    QString oid_;
+    QUrl url_;
+
+    TaskError error_;
+    QString error_string_;
+    int http_error_code_;
+    bool canceled_;
+
+    Progress progress_;
+    bool auto_delete_;
+
+    static QThread *worker_thread_;
+};
+
+
+/**
+ * The downloaded file is first written to a tmp location, then moved
+ * to its final location.
+ */
+class FileDownloadTask : public FileNetworkTask {
+    Q_OBJECT
+public:
+    FileDownloadTask(const Account& account,
+                     const QString& repo_id,
+                     const QString& path,
+                     const QString& local_path,
+                     bool is_save_as_task);
+
+    TaskType type() const { return Download; }
+    QString fileId() const { return file_id_; }
+    bool isSaveAsTask() const { return is_save_as_task_; }
+
+protected:
+    void createFileServerTask(const QString& link);
+    void createGetLinkRequest();
+
+protected slots:
+    void onLinkGet(const QString& link);
+
+private:
+    const bool is_save_as_task_;
+    QString file_id_;
+};
+
+class FileUploadTask : public FileNetworkTask {
+    Q_OBJECT
+public:
+    FileUploadTask(const Account& account,
+                   const QString& repo_id,
+                   const QString& path,
+                   const QString& local_path,
+                   const QString& name,
+                   const bool use_upload = true,
+                   const bool accept_user_confirmation = true);
+
+    // this copy constructor
+    // duplicate a task same with the old one, excluding its internal stage
+    FileUploadTask(const FileUploadTask& rhs);
+
+    void setAcceptUserConfirmation(bool accept) { accept_user_confirmation_ = accept ;}
+
+    // When a file fails to upload, we ask the user to confirm what he wants to
+    // do: retry/skip/abort.
+    //
+    //  - abort: task->cancel()
+    //  - retry: task->continueWithFailedFile(true)
+    //  - skip: task->continueWithFailedFile(false)
+    void continueWithFailedFile(bool retry);
+
+    // Accessors
+    TaskType type() const { return Upload; }
+    const QString& name() const { return name_; }
+    bool useUpload() const { return use_upload_; }
+
+signals:
+    // This signal is meant to be listened by the file progress dialog.
+    void oneFileFailed(const QString& filename, bool single_file);
+
+protected slots:
+    // Here
+    virtual void onOneFileFailed(const QString& filename, bool single_file);
+    void onLinkGetAgain(const QString& link);
+
+protected:
+    virtual void startFileServerTask(const QString& link);
+    void createFileServerTask(const QString& link);
+    void createGetLinkRequest();
+
+    const QString name_;
+
+private:
+    // the copy assignment, delete it;
+    FileUploadTask &operator=(const FileUploadTask& rhs);
+
+    const bool use_upload_;
+    bool accept_user_confirmation_;
+    bool retry_;
+};
+
+class FileUploadMultipleTask : public FileUploadTask {
+    Q_OBJECT
+public:
+    FileUploadMultipleTask(const Account& account,
+                           const QString& repo_id,
+                           const QString& path,
+                           const QString& local_dir_path,
+                           const QStringList& names,
+                           bool use_upload);
+
+    const QStringList& names() const { return names_; }
+    const QStringList& successfulNames();
+
+protected:
+    void createFileServerTask(const QString& link);
+
+    const QStringList names_;
+};
+
+class FileUploadDirectoryTask : public FileUploadTask {
+    Q_OBJECT
+public:
+    FileUploadDirectoryTask(const Account& account,
+                            const QString& repo_id,
+                            const QString& path,
+                            const QString& local_path,
+                            const QString& name);
+
+protected:
+    void createFileServerTask(const QString& link);
+
+protected slots:
+    // overwrited
+    virtual void onFinished(bool success);
+
+private slots:
+    void nextEmptyFolder();
+    void onCreateDirFailed(const ApiError& error);
+
+private:
+    QStringList empty_subfolders_;
+    QScopedPointer<CreateDirectoryRequest, QScopedPointerDeleteLater> create_dir_req_;
+};
+
+/**
+ * Handles raw file download/upload with seafile file server.
+ *
+ * This is the base class for file upload/download task. The task runs in a
+ * seperate thread, which means we can not invoke non-const methods of it from
+ * the main thread. To start the task: use QMetaObject::invokeMethod to call
+ * the start() member function. task. The same for canceling the task.
+ *
+ * @abstract
+ */
+class FileServerTask : public QObject {
+    Q_OBJECT
+public:
+    FileServerTask(const QUrl& url,
+                   const QString& local_path);
+    virtual ~FileServerTask();
+
+    virtual void continueWithFailedFile(bool retry, const QString& link) {};
+
+    // accessors
+    const FileNetworkTask::TaskError& error() const { return error_; }
+    const QString& errorString() const { return error_string_; }
+    int httpErrorCode() const { return http_error_code_; }
+    virtual const QString& oid() const { return oid_; }
+    int retryCount() const { return retry_count_; }
+    const QString& failedPath() const { return failed_path_; }
+    bool canceled() const { return canceled_; }
+    QUrl url() const { return url_; }
+
+    static void resetQNAM();
+
+signals:
+    void progressUpdate(qint64 transferred, qint64 total);
+    void nameUpdate(QString current_name);
+    void finished(bool success);
+    void retried(int retry_count);
+
+signals:
+    void oneFileFailed(const QString& filename, bool single_file);
+
+public slots:
+    void start();
+    virtual void cancel();
+
+protected slots:
+    void onSslErrors(const QList<QSslError>& errors);
+    void httpRequestFinished();
+    void retry();
+    void doAbort();
+
+protected:
+    /**
+     * Prepare the initialization work, like creating the tmp file, or open the
+     * uploaded file for reading. It may be called again when retrying a task.
+     */
+    virtual void prepare() = 0;
+
+    /**
+     * If return true, the request would be retried for a few times when error
+     * happened. By default the request is not retried. Subclasses can overwrite
+     * this function to enable retry.
+     */
+    virtual bool retryEnabled();
+
+    /**
+     * Send the http request.
+     * This member function may be called in two places:
+     * 1. when task is first started
+     * 2. when the request is redirected
+     */
+    virtual void sendRequest() = 0;
+    virtual void onHttpRequestFinished() = 0;
+    bool handleHttpRedirect();
+    bool maybeRetry();
+    void setError(FileNetworkTask::TaskError error, const QString& error_string);
+    void setHttpError(int code);
+
+    // Always use this to access the network access manager, instead of using
+    // network_mgr_ directly, because it handles the network status change
+    // detection.
+    QNetworkAccessManager *getQNAM();
+
+    QUrl url_;
+    QString local_path_;
+    QString failed_path_;
+    QString oid_;
+
+    QNetworkReply *reply_;
+    bool canceled_;
+    int redirect_count_;
+    int retry_count_;
+
+    FileNetworkTask::TaskError error_;
+    QString error_string_;
+    int http_error_code_;
+};
+
+class GetFileTask : public FileServerTask {
+    Q_OBJECT
+public:
+    GetFileTask(const QUrl& url, const QString& local_path);
+    ~GetFileTask();
+
+protected:
+    void prepare();
+    void sendRequest();
+    void onHttpRequestFinished();
+
+private slots:
+    void httpReadyRead();
+
+private:
+    QTemporaryFile *tmp_file_;
+};
+
+class PostFilesTask : public FileServerTask {
+    Q_OBJECT
+public:
+    PostFilesTask(const QUrl& url,
+                  const QString& parent_dir,
+                  const QString& local_path,
+                  const QStringList& names,
+                  const bool use_relative);
+    ~PostFilesTask();
+    int currentNum();
+
+    const QStringList& successfulNames() const { return successful_names_; }
+
+    void continueWithFailedFile(bool retry, const QString& link);
+
+protected:
+    void prepare();
+    void sendRequest();
+    void startNext(const QString& link = QString());
+
+private slots:
+    void cancel();
+    void onProgressUpdate();
+    void onPostTaskProgressUpdate(qint64, qint64);
+    void onPostTaskFinished(bool success);
+
+private:
+    // never used
+    void onHttpRequestFinished() {}
+
+    const QString parent_dir_;
+    const QString name_;
+    QList<qint64> file_sizes_;
+    const QStringList names_;
+    QStringList successful_names_;
+
+    QString current_name_;
+
+    QScopedPointer<ReliablePostFileTask, doDeleteLater<ReliablePostFileTask> > task_;
+    int current_num_;
+    // transferred bytes in the current tasks
+    qint64 current_bytes_;
+    // the total bytes of completely transferred tasks
+    qint64 transferred_bytes_;
+    // the total bytes of all tasks
+    qint64 total_bytes_;
+    // deal with the qt4 eventloop's bug
+    QTimer *progress_update_timer_;
+    const bool use_relative_;
+};
+
+#endif // SEAFILE_CLIETN_FILEBROWSER_TAKS_H
diff --git a/src/filebrowser/thumbnail-service.cpp b/src/filebrowser/thumbnail-service.cpp
new file mode 100644 (file)
index 0000000..c601e61
--- /dev/null
@@ -0,0 +1,350 @@
+#include <QDir>
+#include <QImage>
+#include <QQueue>
+#include <QHash>
+#include <QTimer>
+#include <QDateTime>
+
+#include "../seafile-applet.h"
+#include "../configurator.h"
+#include "../account-mgr.h"
+#include "../api/requests.h"
+#include "../utils/paint-utils.h"
+#include "../utils/utils.h"
+#include "../utils/file-utils.h"
+
+#include "thumbnail-service.h"
+
+static const int kCheckPendingInterval = 1000; // 1s
+static const qint64 kExpireTimeIntevalMsec = 300 * 1000; // 5min
+
+struct PendingRequestInfo {
+    int last_wait;
+    int time_to_wait;
+
+    void backoff() {
+        last_wait = qMax(last_wait, 1) * 2;
+        time_to_wait = last_wait;
+    }
+
+    bool isReady() {
+        return time_to_wait == 0;
+    }
+
+    void tick() {
+        time_to_wait = qMax(0, time_to_wait - 1);
+    }
+};
+
+struct ThumbnailKey {
+    QString repo_id;
+    QString path;
+    QString dirent_id;
+    uint size;
+
+    bool operator == (const ThumbnailKey &key) const {
+        return repo_id == key.repo_id &&
+               path == key.path &&
+              dirent_id == key.dirent_id &&
+              size == key.size;
+    }
+};
+
+uint qHash(const ThumbnailKey &key) {
+       QString size;
+       size.setNum(key.size);
+       const QString key_str = key.repo_id + 
+                               key.path + 
+                               key.dirent_id + 
+                               size;
+       return qHash(key_str);
+}
+
+class PendingThumbnailRequestQueue
+{
+public:
+    PendingThumbnailRequestQueue() {};
+
+    void enqueue(const QString& repo_id, 
+                const QString& path, 
+                const QString& dirent_id,
+                uint size) 
+    {
+        ThumbnailKey key;
+       key.repo_id = repo_id;
+       key.path = path;
+       key.dirent_id = dirent_id;
+       key.size = size;
+
+        if (q_.contains(key)) {
+            return;
+        }
+        // if we have set an expire time, and we haven't reached it yet
+        if (expire_time_.contains(key) &&
+            QDateTime::currentMSecsSinceEpoch() <= expire_time_[key]) {
+            return;
+        }
+        // update expire time
+        expire_time_[key] = QDateTime::currentMSecsSinceEpoch() + kExpireTimeIntevalMsec;
+
+        q_.enqueue(key);
+    }
+
+    void enqueueAndBackoff(const QString& repo_id, 
+                          const QString& path, 
+                          const QString& dirent_id,
+                          uint size) 
+    {
+        ThumbnailKey key;
+       key.repo_id = repo_id;
+       key.path = path;
+       key.dirent_id = dirent_id;
+       key.size = size;
+
+        PendingRequestInfo& info = wait_[key];
+        info.backoff();
+
+        enqueue(repo_id, path, dirent_id, size);
+    }
+
+    void clearWait(const QString& repo_id, 
+                  const QString& path, 
+                  const QString& dirent_id,
+                  uint size) 
+    {
+        ThumbnailKey key;
+       key.repo_id = repo_id;
+       key.path = path;
+       key.dirent_id = dirent_id;
+       key.size = size;
+
+        wait_.remove(key);
+    }
+
+    void tick() {
+        if (q_.isEmpty())
+           return;
+
+        QListIterator<ThumbnailKey> iter(q_);
+
+        while (iter.hasNext()) {
+           ThumbnailKey key;
+                   key.repo_id = iter.peekNext().repo_id;
+           key.path = iter.peekNext().path;    
+           key.dirent_id = iter.peekNext().dirent_id;
+           key.size = iter.next().size;
+
+            if (wait_.contains(key)) {
+                PendingRequestInfo& info = wait_[key];
+                info.tick();
+            }
+        }
+    }
+
+    ThumbnailKey dequeue() {
+        ThumbnailKey key, key_default;
+       key_default.repo_id = QString();
+       key_default.path = QString();
+       key_default.dirent_id = QString();
+       key_default.size = 0;
+
+        int i = 0, n = q_.size();
+        while (i++ < n) {
+            if (q_.isEmpty()) {
+                return key_default;
+            }
+
+            key = q_.dequeue();
+
+            PendingRequestInfo info = wait_.value(key);
+            if (info.isReady()) {
+                return key;
+            } else {
+                q_.enqueue(key);
+            }
+        }
+
+        return key_default;
+    }
+
+    void reset() {
+        q_.clear();
+        wait_.clear();
+        expire_time_.clear();
+    }
+
+private:
+    QQueue<ThumbnailKey> q_;
+
+    QHash<ThumbnailKey, PendingRequestInfo> wait_;
+    QHash<ThumbnailKey, qint64> expire_time_;
+};
+
+ThumbnailService* ThumbnailService::singleton_ = NULL;
+
+ThumbnailService* ThumbnailService::instance()
+{
+    if (singleton_ == NULL) {
+        static ThumbnailService instance;
+        singleton_ = &instance;
+    }
+
+    return singleton_;
+}
+
+
+ThumbnailService::ThumbnailService(QObject *parent)
+    : QObject(parent), 
+      get_thumbnail_req_(NULL)
+{
+    queue_ = new PendingThumbnailRequestQueue;
+
+    timer_ = new QTimer(this);
+
+    connect(timer_, SIGNAL(timeout()), this, SLOT(checkPendingRequests()));
+
+}
+
+void ThumbnailService::start()
+{
+    timer_->start(kCheckPendingInterval);
+}
+
+// check in-memory-cache
+QPixmap ThumbnailService::loadThumbnailFromLocal(const QString& repo_id, 
+                                                 const QString& path,
+                                                 const QString& dirent_id,
+                                                uint size)
+{
+    QPixmap ret;
+
+    QString key = getPixmapCacheKey(repo_id, path, dirent_id, size);
+    if (cache_.find(key, &ret)) {
+        return ret;
+    }
+    
+    return ret;
+}
+
+QString ThumbnailService::getPixmapCacheKey(const QString& repo_id, 
+                                           const QString& path, 
+                                            const QString& dirent_id,
+                                           uint size)
+{
+    const Account& account = seafApplet->accountManager()->accounts().front();
+    QString size_str;
+    size_str.setNum(size);
+    return QDir(thumbnails_dir_).filePath(::md5(account.serverUrl.host()
+                                               + account.username
+                                                + repo_id 
+                                                + path
+                                               + dirent_id
+                                               + size_str));
+}
+
+void ThumbnailService::fetchImageFromServer(const QString& repo_id, 
+                                            const QString& path,
+                                            const QString& dirent_id,
+                                           uint size)
+{
+    if (get_thumbnail_req_) {
+        if (repo_id == get_thumbnail_req_->repoId() &&
+            path == get_thumbnail_req_->path() &&
+           dirent_id == get_thumbnail_req_->direntId() &&
+           size == get_thumbnail_req_->size()) {
+            return;
+        }
+        queue_->enqueue(repo_id, path, dirent_id, size);
+        return;
+    }
+
+    const Account& account = seafApplet->accountManager()->accounts().front();
+
+    get_thumbnail_req_ = new GetThumbnailRequest(account, 
+                                                 repo_id, 
+                                                 path, 
+                                                dirent_id,
+                                                 size);
+
+    connect(get_thumbnail_req_, SIGNAL(success(const QPixmap&)),
+            this, SLOT(onGetThumbnailSuccess(const QPixmap&)));
+    connect(get_thumbnail_req_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetThumbnailFailed(const ApiError&)));
+
+    get_thumbnail_req_->send();
+}
+
+void ThumbnailService::onGetThumbnailSuccess(const QPixmap& img)
+{
+    const QString repo_id = get_thumbnail_req_->repoId();
+    const QString path_in_repo = get_thumbnail_req_->path();
+    const QString dirent_id = get_thumbnail_req_->direntId();
+    const uint size = get_thumbnail_req_->size();
+    
+    QString key = getPixmapCacheKey(repo_id, path_in_repo, dirent_id, size);
+
+    cache_.insert(key, img);
+
+    emit thumbnailUpdated(img, path_in_repo);
+
+    get_thumbnail_req_->deleteLater();
+    get_thumbnail_req_ = NULL;
+
+    queue_->clearWait(repo_id, path_in_repo, dirent_id, size);
+}
+
+void ThumbnailService::onGetThumbnailFailed(const ApiError& error)
+{
+    const QString repo_id = get_thumbnail_req_->repoId();
+    const QString path = get_thumbnail_req_->path();
+    const QString dirent_id = get_thumbnail_req_->direntId();
+    const uint size = get_thumbnail_req_->size();
+
+    get_thumbnail_req_->deleteLater();
+    get_thumbnail_req_ = NULL;
+
+    queue_->enqueueAndBackoff(repo_id, path, dirent_id, size);
+}
+
+QPixmap ThumbnailService::getThumbnail(const QString& repo_id, 
+                                       const QString& path,
+                                      const QString& dirent_id,
+                                      uint size)
+{
+    QPixmap img = loadThumbnailFromLocal(repo_id, path, dirent_id, size);
+
+    // update all thumbnails if img is null
+    if (img.isNull()) {
+        if (!get_thumbnail_req_ || 
+           get_thumbnail_req_->repoId() != repo_id || 
+           get_thumbnail_req_->path() != path ||
+           get_thumbnail_req_->direntId() != dirent_id ||
+           get_thumbnail_req_->size() != size) 
+       {
+            queue_->enqueue(repo_id, path, dirent_id, size);
+        }
+    }
+    if (img.isNull()) {
+        return QIcon(":/images/files_v2/file_image.png").pixmap(24);
+    } else {
+        return img;
+    }
+}
+
+void ThumbnailService::checkPendingRequests()
+{
+    queue_->tick();
+
+    if (get_thumbnail_req_ != NULL) {
+        return;
+    }
+
+    ThumbnailKey key = queue_->dequeue();
+    QString repo_id = key.repo_id;
+    QString path = key.path;
+    QString dirent_id = key.dirent_id;
+    uint size = key.size;
+    if (!repo_id.isEmpty()) {
+        fetchImageFromServer(repo_id, path, dirent_id, size);
+    }
+}
diff --git a/src/filebrowser/thumbnail-service.h b/src/filebrowser/thumbnail-service.h
new file mode 100644 (file)
index 0000000..49ae544
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef SEAFILE_CLIENT_THUMBNAIL_SERVICE_H
+#define SEAFILE_CLIENT_THUMBNAIL_SERVICE_H
+
+#include <vector>
+#include <QObject>
+#include <QImage>
+#include <QPixmapCache>
+#include <QString>
+#include <QPixmap>
+
+class QTimer;
+
+class Account;
+class ApiError;
+class GetThumbnailRequest;
+class PendingThumbnailRequestQueue;
+
+
+class ThumbnailService : public QObject
+{
+    Q_OBJECT
+public:
+    static ThumbnailService* instance();
+
+    void start();
+
+    QPixmap getThumbnail(const QString& repo_id, 
+                        const QString& path, 
+                        const QString& dirent_id,
+                        uint thumbnail_default_size = 28);
+
+signals:
+    void thumbnailUpdated(const QPixmap& thumbnail, const QString& path);
+
+private slots:
+    void onGetThumbnailSuccess(const QPixmap& thumbnail);
+    void onGetThumbnailFailed(const ApiError& error);
+    void checkPendingRequests();
+
+private:
+    Q_DISABLE_COPY(ThumbnailService)
+
+    ThumbnailService(QObject *parent=0);
+
+    static ThumbnailService *singleton_;
+
+    QPixmap loadThumbnailFromLocal(const QString& repo_id, 
+                                  const QString& path,
+                                   const QString& dirent_id,
+                                  uint size);
+    QString getPixmapCacheKey(const QString& repo_id, 
+                             const QString& path, 
+                              const QString& dirent_id,
+                             uint size);
+    void fetchImageFromServer(const QString& repo_id, 
+                             const QString& path, 
+                              const QString& dirent_id,
+                             uint size);
+    
+    GetThumbnailRequest *get_thumbnail_req_;
+
+    QString thumbnails_dir_;
+
+    QPixmapCache cache_;
+
+    PendingThumbnailRequestQueue *queue_;
+
+    QTimer *timer_;
+    
+};
+
+#endif // SEAFILE_CLIENT_AVATAR_SERVICE_H
diff --git a/src/filebrowser/transfer-mgr.cpp b/src/filebrowser/transfer-mgr.cpp
new file mode 100644 (file)
index 0000000..3430e9e
--- /dev/null
@@ -0,0 +1,144 @@
+#include <errno.h>
+#include <stdio.h>
+#include <sqlite3.h>
+
+#include <QDateTime>
+#include <QTimer>
+#include <QDir>
+
+#include "utils/file-utils.h"
+#include "utils/utils.h"
+#include "configurator.h"
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "file-browser-requests.h"
+#include "tasks.h"
+#include "auto-update-mgr.h"
+#include "data-cache.h"
+#include "data-mgr.h"
+
+#include "transfer-mgr.h"
+
+namespace {
+
+bool isDownloadForGivenParentDir(FileDownloadTask* task,
+                                 const QString& repo_id,
+                                 const QString& parent_dir)
+{
+    return task && task->repoId() == repo_id &&
+        ::getParentPath(task->path()) == parent_dir;
+}
+
+bool matchDownloadTask(FileDownloadTask* task,
+                       const QString& repo_id,
+                       const QString& path)
+{
+    return task && task->repoId() == repo_id && task->path() == path;
+}
+
+} // namespace
+
+SINGLETON_IMPL(TransferManager)
+
+TransferManager::TransferManager()
+{
+}
+
+TransferManager::~TransferManager()
+{
+}
+
+FileDownloadTask* TransferManager::addDownloadTask(const Account& account,
+                                                   const QString& repo_id,
+                                                   const QString& path,
+                                                   const QString& local_path,
+                                                   bool is_save_as_task)
+{
+    FileDownloadTask* existing_task = getDownloadTask(repo_id, path);
+    if (existing_task) {
+        return existing_task;
+    }
+
+    FileDownloadTask* task = new FileDownloadTask(account, repo_id, path, local_path, is_save_as_task);
+    connect(task, SIGNAL(finished(bool)),
+            this, SLOT(onDownloadTaskFinished(bool)));
+    if (current_download_) {
+        pending_downloads_.enqueue(task);
+    } else {
+        startDownloadTask(task);
+    }
+    return task;
+}
+
+void TransferManager::onDownloadTaskFinished(bool success)
+{
+    FileDownloadTask *task = (FileDownloadTask *)sender();
+    if (task == current_download_) {
+        current_download_ = nullptr;
+        if (!pending_downloads_.empty()) {
+            FileDownloadTask* task = pending_downloads_.dequeue();
+            startDownloadTask(task);
+        }
+    } else {
+        pending_downloads_.removeOne(task);
+    }
+}
+
+void TransferManager::startDownloadTask(FileDownloadTask* task)
+{
+    current_download_ = task;
+    task->start();
+}
+
+FileDownloadTask* TransferManager::getDownloadTask(const QString& repo_id,
+                                                   const QString& path)
+{
+    qDebug("get download task repo_id is %s, path is %s",
+           repo_id.toUtf8().data(), path.toUtf8().data());
+    if (matchDownloadTask(current_download_, repo_id, path)) {
+        return current_download_;
+    }
+    foreach (FileDownloadTask* task, pending_downloads_) {
+        if (matchDownloadTask(task, repo_id, path)) {
+            return task;
+        }
+    }
+    return NULL;
+}
+
+void TransferManager::cancelDownload(const QString& repo_id,
+                                     const QString& path)
+{
+    FileDownloadTask* task = getDownloadTask(repo_id, path);
+    if (!task)
+        return;
+    // If the task is a pending one, it would be removed from queue in
+    // ::onDownloadTaskFinished slot.
+    task->cancel();
+}
+
+void TransferManager::cancelAllDownloadTasks()
+{
+    if (current_download_) {
+        current_download_->cancel();
+        current_download_= nullptr;
+    }
+    pending_downloads_.clear();
+}
+
+QList<FileDownloadTask*>
+TransferManager::getDownloadTasks(const QString& repo_id,
+                                  const QString& parent_dir)
+{
+    QList<FileDownloadTask*> tasks;
+    if (isDownloadForGivenParentDir(current_download_, repo_id, parent_dir)) {
+        tasks.append(current_download_);
+    }
+    foreach (FileDownloadTask* task, pending_downloads_) {
+        if (isDownloadForGivenParentDir(task, repo_id, parent_dir)) {
+            tasks.append(task);
+        }
+    }
+
+    return tasks;
+}
diff --git a/src/filebrowser/transfer-mgr.h b/src/filebrowser/transfer-mgr.h
new file mode 100644 (file)
index 0000000..1d822d3
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_TRANSFER_MANAGER_H
+#define SEAFILE_CLIENT_FILE_BROWSER_TRANSFER_MANAGER_H
+
+#include <QObject>
+#include <QQueue>
+
+#include "api/api-error.h"
+#include "seaf-dirent.h"
+#include "utils/singleton.h"
+
+
+template<typename Key> class QQueue;
+
+class QThread;
+
+class Account;
+class SeafileApiRequest;
+class GetDirentsRequest;
+class DirentsCache;
+class FileCache;
+class FileUploadTask;
+class FileDownloadTask;
+class FileNetworkTask;
+
+/**
+ * TransferManager manages all upload/download tasks.
+ *
+ * There is a pending tasks queue for all download tasks. At any moment only
+ * one download task is running, others are waiting in the queue.
+ *
+ */
+class TransferManager : public QObject {
+    SINGLETON_DEFINE(TransferManager)
+    Q_OBJECT
+public:
+    TransferManager();
+    ~TransferManager();
+
+    FileDownloadTask* addDownloadTask(const Account& account,
+                                      const QString& repo_id,
+                                      const QString& path,
+                                      const QString& local_path,
+                                      bool is_save_as_task = false);
+
+    FileDownloadTask* getDownloadTask(const QString& repo_id,
+                                      const QString& path);
+
+    void cancelDownload(const QString& repo_id, const QString& path);
+    void cancelAllDownloadTasks();
+
+    /**
+     * Return all download tasks for files in the `parent_dir`
+     */
+    QList<FileDownloadTask*> getDownloadTasks(const QString& repo_id,
+                                              const QString& parent_dir);
+
+private slots:
+    void onDownloadTaskFinished(bool success);
+
+private:
+    void startDownloadTask(FileDownloadTask* task);
+
+    FileDownloadTask* current_download_;
+    QQueue<FileDownloadTask*> pending_downloads_;
+};
+
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_TRANSFER_MANAGER_H
diff --git a/src/finder-sync/finder-sync-host.cpp b/src/finder-sync/finder-sync-host.cpp
new file mode 100644 (file)
index 0000000..c1aca23
--- /dev/null
@@ -0,0 +1,317 @@
+#include "finder-sync/finder-sync-host.h"
+
+#include <vector>
+#include <mutex>
+#include <memory>
+
+#include <QDir>
+#include <QFileInfo>
+
+#include "account.h"
+#include "account-mgr.h"
+#include "auto-login-service.h"
+#include "settings-mgr.h"
+#include "seafile-applet.h"
+#include "daemon-mgr.h"
+#include "rpc/local-repo.h"
+#include "rpc/rpc-client.h"
+#include "filebrowser/file-browser-requests.h"
+#include "filebrowser/sharedlink-dialog.h"
+#include "filebrowser/seafilelink-dialog.h"
+#include "utils/utils.h"
+
+enum PathStatus {
+    SYNC_STATUS_NONE = 0,
+    SYNC_STATUS_SYNCING,
+    SYNC_STATUS_ERROR,
+    SYNC_STATUS_IGNORED,
+    SYNC_STATUS_SYNCED,
+    SYNC_STATUS_READONLY,
+    SYNC_STATUS_PAUSED,
+    SYNC_STATUS_LOCKED,
+    SYNC_STATUS_LOCKED_BY_ME,
+    MAX_SYNC_STATUS,
+};
+
+namespace {
+struct QtLaterDeleter {
+public:
+  void operator()(QObject *ptr) {
+    ptr->deleteLater();
+  }
+};
+} // anonymous namespace
+
+static const char *const kPathStatus[] = {
+    "none", "syncing", "error", "ignored", "synced", "readonly", "paused", "locked", "locked_by_me", NULL,
+};
+
+static inline PathStatus getPathStatusFromString(const QString &status) {
+    for (int p = SYNC_STATUS_NONE; p < MAX_SYNC_STATUS; ++p)
+        if (kPathStatus[p] == status)
+            return static_cast<PathStatus>(p);
+    return SYNC_STATUS_NONE;
+}
+
+inline static bool isContainsPrefix(const QString &path,
+                                    const QString &prefix) {
+    if (prefix.size() > path.size())
+        return false;
+    if (!path.startsWith(prefix))
+        return false;
+    if (prefix.size() < path.size() && path[prefix.size()] != '/')
+        return false;
+    return true;
+}
+
+static std::mutex update_mutex_;
+static std::vector<LocalRepo> watch_set_;
+static std::unique_ptr<GetSharedLinkRequest, QtLaterDeleter> get_shared_link_req_;
+static std::unique_ptr<LockFileRequest, QtLaterDeleter> lock_file_req_;
+
+FinderSyncHost::FinderSyncHost() : rpc_client_(new SeafileRpcClient) {
+    rpc_client_->tryConnectDaemon();
+    connect(seafApplet->daemonManager(), SIGNAL(daemonRestarted()), this, SLOT(onDaemonRestarted()));
+}
+
+FinderSyncHost::~FinderSyncHost() {
+    get_shared_link_req_.reset();
+    lock_file_req_.reset();
+}
+
+void FinderSyncHost::onDaemonRestarted()
+{
+    qDebug("reviving rpc client when daemon is restarted");
+    if (rpc_client_) {
+        delete rpc_client_;
+    }
+    rpc_client_ = new SeafileRpcClient();
+    rpc_client_->tryConnectDaemon();
+}
+
+utils::BufferArray FinderSyncHost::getWatchSet(size_t header_size,
+                                               int max_size) {
+    updateWatchSet(); // lock is inside
+
+    std::unique_lock<std::mutex> lock(update_mutex_);
+
+    std::vector<QByteArray> array;
+    size_t byte_count = header_size;
+
+    unsigned count = (max_size >= 0 && watch_set_.size() > (unsigned)max_size)
+                         ? max_size
+                         : watch_set_.size();
+    for (unsigned i = 0; i < count; ++i) {
+        const LocalRepo& repo = watch_set_[i];
+        QString internal_link_supported = repo.account.isAtLeastVersion(6, 3, 0)
+            ? "internal-link-supported"
+            : "internal-link-unsupported";
+        QString content = repo.worktree;
+        content += "\t" + internal_link_supported;
+        array.emplace_back(content.toUtf8());
+        byte_count += 36 + array.back().size() + 3;
+    }
+    // rount byte_count to longword-size
+    size_t round_end = byte_count & 3;
+    if (round_end)
+        byte_count += 4 - round_end;
+
+    utils::BufferArray retval;
+    retval.resize(byte_count);
+
+    // zeroize rounds
+    switch (round_end) {
+    case 1:
+        retval[byte_count - 3] = '\0';
+    case 2:
+        retval[byte_count - 2] = '\0';
+    case 3:
+        retval[byte_count - 1] = '\0';
+    default:
+        break;
+    }
+
+    assert(retval.size() == byte_count);
+    char *pos = retval.data() + header_size;
+    for (unsigned i = 0; i != count; ++i) {
+        // copy repo_id
+        memcpy(pos, watch_set_[i].id.toUtf8().data(), 36);
+        pos += 36;
+        // copy worktree
+        memcpy(pos, array[i].data(), array[i].size() + 1);
+        pos += array[i].size() + 1;
+        // copy status
+        *pos++ = watch_set_[i].sync_state;
+        *pos++ = '\0';
+    }
+
+    return retval;
+}
+
+void FinderSyncHost::updateWatchSet() {
+    std::unique_lock<std::mutex> lock(update_mutex_);
+
+    // update watch_set_
+    if (rpc_client_->listLocalRepos(&watch_set_)) {
+        qWarning("[FinderSync] update watch set failed");
+        watch_set_.clear();
+        return;
+    }
+    for (LocalRepo &repo : watch_set_) {
+        rpc_client_->getSyncStatus(repo);
+        repo.account = seafApplet->accountManager()->getAccountByRepo(repo.id, rpc_client_);
+    }
+    lock.unlock();
+}
+
+uint32_t FinderSyncHost::getFileStatus(const char *repo_id, const char *path) {
+    std::unique_lock<std::mutex> lock(update_mutex_);
+
+    QString repo = QString::fromUtf8(repo_id, 36);
+    QString path_in_repo = path;
+    QString status;
+    bool isDirectory = path_in_repo.endsWith('/');
+    if (isDirectory)
+        path_in_repo.resize(path_in_repo.size() - 1);
+    if (rpc_client_->getRepoFileStatus(
+            repo,
+            path_in_repo,
+            isDirectory, &status) != 0) {
+        return PathStatus::SYNC_STATUS_NONE;
+    }
+
+    return getPathStatusFromString(status);
+}
+
+void FinderSyncHost::doShareLink(const QString &path) {
+    QString repo_id;
+    Account account;
+    QString path_in_repo;
+    if (!lookUpFileInformation(path, &repo_id, &account, &path_in_repo)) {
+        qWarning("[FinderSync] invalid path %s", path.toUtf8().data());
+        return;
+    }
+
+    get_shared_link_req_.reset(new GetSharedLinkRequest(
+        account, repo_id, QString("/").append(path_in_repo),
+        QFileInfo(path).isFile()));
+
+    connect(get_shared_link_req_.get(), SIGNAL(success(const QString &, const QString&)), this,
+            SLOT(onShareLinkGenerated(const QString &)));
+
+    get_shared_link_req_->send();
+}
+
+void FinderSyncHost::doInternalLink(const QString &path)
+{
+    QString repo_id;
+    Account account;
+    QString path_in_repo;
+    if (!lookUpFileInformation(path, &repo_id, &account, &path_in_repo)) {
+        qWarning("[FinderSync] invalid path %s", path.toUtf8().data());
+        return;
+    }
+
+    GetSmartLinkRequest *req = new GetSmartLinkRequest(account, repo_id, path_in_repo, path_in_repo.endsWith('/'));
+    connect(req, SIGNAL(success(const QString&)),
+            this, SLOT(onGetSmartLinkSuccess(const QString&)));
+    connect(req, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetSmartLinkFailed(const ApiError&)));
+
+    req->send();
+}
+
+void FinderSyncHost::onGetSmartLinkSuccess(const QString& smart_link)
+{
+    SeafileLinkDialog *dialog = new SeafileLinkDialog(smart_link);
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->show();
+    dialog->raise();
+    dialog->activateWindow();
+}
+
+void FinderSyncHost::onGetSmartLinkFailed(const ApiError& error)
+{
+    seafApplet->warningBox(tr("Failed to get link"));
+}
+
+void FinderSyncHost::doLockFile(const QString &path, bool lock)
+{
+    QString repo_id;
+    Account account;
+    QString path_in_repo;
+    if (!lookUpFileInformation(path, &repo_id, &account, &path_in_repo)) {
+        qWarning("[FinderSync] invalid path %s", path.toUtf8().data());
+        return;
+    }
+    lock_file_req_.reset(new LockFileRequest(account, repo_id, path_in_repo, lock));
+
+    connect(lock_file_req_.get(), SIGNAL(success()),
+            this, SLOT(onLockFileSuccess()));
+    lock_file_req_->send();
+}
+
+void FinderSyncHost::onShareLinkGenerated(const QString &link)
+{
+    SharedLinkDialog *dialog = new SharedLinkDialog(link, NULL);
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->show();
+    dialog->raise();
+    dialog->activateWindow();
+}
+
+void FinderSyncHost::onLockFileSuccess()
+{
+    LockFileRequest* req = qobject_cast<LockFileRequest*>(sender());
+    if (!req)
+        return;
+    rpc_client_->markFileLockState(req->repoId(), req->path(), req->lock());
+}
+
+bool FinderSyncHost::lookUpFileInformation(const QString &path, QString *repo_id, Account *account, QString *path_in_repo)
+{
+    QString worktree;
+    // work in a mutex
+    {
+        std::unique_lock<std::mutex> watch_set_lock(update_mutex_);
+        for (const LocalRepo &repo : watch_set_)
+            if (isContainsPrefix(path, repo.worktree)) {
+                *repo_id = repo.id;
+                worktree = repo.worktree;
+                break;
+            }
+    }
+    if (worktree.isEmpty() || repo_id->isEmpty())
+        return false;
+
+    *path_in_repo = QDir(worktree).relativeFilePath(path);
+    if (!path_in_repo->startsWith("/"))
+        *path_in_repo = "/" + *path_in_repo;
+    if (path.endsWith("/"))
+        *path_in_repo += "/";
+
+    // we have a empty path_in_repo representing the root of the directory,
+    // and we are okay!
+    if (path_in_repo->startsWith("."))
+        return false;
+
+    *account = seafApplet->accountManager()->getAccountByRepo(*repo_id);
+    if (!account->isValid())
+        return false;
+
+    return true;
+}
+
+void FinderSyncHost::doShowFileHistory(const QString &path)
+{
+    QString repo_id;
+    Account account;
+    QString path_in_repo;
+    if (!lookUpFileInformation(path, &repo_id, &account, &path_in_repo)) {
+        qWarning("[FinderSync] invalid path %s", path.toUtf8().data());
+        return;
+    }
+    QUrl url = "/repo/file_revisions/" + repo_id + "/";
+    url = ::includeQueryParams(url, {{"p", path_in_repo}});
+    AutoLoginService::instance()->startAutoLogin(url.toString());
+}
diff --git a/src/finder-sync/finder-sync-host.h b/src/finder-sync/finder-sync-host.h
new file mode 100644 (file)
index 0000000..210d3ae
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef SEAFILE_CLIENT_FINDER_SYNC_HOST_H_
+#define SEAFILE_CLIENT_FINDER_SYNC_HOST_H_
+#include <QObject>
+#include <QString>
+#include <cstdint>
+#include <vector>
+#include "utils/stl.h"
+#include "api/api-error.h"
+
+const int kPathMaxSize = 1024;
+
+class Account;
+class SeafileRpcClient;
+class FinderSyncHost : public QObject {
+    Q_OBJECT
+public:
+    FinderSyncHost();
+    ~FinderSyncHost();
+    // called from another thread
+    utils::BufferArray getWatchSet(size_t header_size, int max_size = -1);
+    // called from another thread
+    uint32_t getFileStatus(const char* repo_id, const char* path);
+private slots:
+    void onDaemonRestarted();
+    void updateWatchSet();
+    void doLockFile(const QString &path, bool lock);
+    void doShareLink(const QString &path);
+    void doInternalLink(const QString &path);
+    void onShareLinkGenerated(const QString& link);
+    void onLockFileSuccess();
+    void doShowFileHistory(const QString& path);
+    void onGetSmartLinkSuccess(const QString& smart_link);
+    void onGetSmartLinkFailed(const ApiError& error);
+private:
+    bool lookUpFileInformation(const QString &path, QString *repo_id, Account *account, QString *path_in_repo);
+    SeafileRpcClient *rpc_client_;
+};
+
+#endif // SEAFILE_CLIENT_FINDER_SYNC_HOST_H_
diff --git a/src/finder-sync/finder-sync-listener.h b/src/finder-sync/finder-sync-listener.h
new file mode 100644 (file)
index 0000000..344d8f2
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SEAFILE_CLIENT_FINDER_SYNC_LISTENER_H_
+#define SEAFILE_CLIENT_FINDER_SYNC_LISTENER_H_
+
+/// \brief start the listener
+///
+void finderSyncListenerStart();
+
+/// \brief stop the listener
+///
+void finderSyncListenerStop();
+
+#endif // SEAFILE_CLIENT_FINDER_SYNC_LISTENER_H_
diff --git a/src/finder-sync/finder-sync-listener.mm b/src/finder-sync/finder-sync-listener.mm
new file mode 100644 (file)
index 0000000..e48be8a
--- /dev/null
@@ -0,0 +1,297 @@
+#include "finder-sync/finder-sync-host.h"
+#include "finder-sync/finder-sync-listener.h"
+
+#include <libkern/OSAtomic.h>
+#include <mach/mach.h>
+#import <Cocoa/Cocoa.h>
+
+#if !__has_feature(objc_arc)
+#error this file must be built with ARC support
+#endif
+
+@interface FinderSyncListener : NSObject <NSMachPortDelegate>
+@end
+//
+// MachPort Message
+// - mach_msg_header_t command
+// - uint32_t version
+// - uint32_t command
+// - body
+// - mach_msg_trailer_t trailer (for rcv only)
+//
+//
+
+namespace {
+enum CommandType : uint32_t {
+    GetWatchSet = 0,
+    DoShareLink = 1,
+    DoGetFileStatus = 2,
+    DoInternalLink = 3,
+    DoLockFile = 4,
+    DoUnlockFile = 5,
+    DoShowFileHistory = 6,
+};
+
+struct mach_msg_command_send_t {
+    mach_msg_header_t header;
+    uint32_t version;
+    uint32_t command;
+    char repo[36];
+    char body[kPathMaxSize];
+};
+
+struct mach_msg_command_rcv_t {
+    mach_msg_header_t header;
+    uint32_t version;
+    uint32_t command;
+    char repo[36];
+    char body[kPathMaxSize];
+    mach_msg_trailer_t trailer;
+};
+
+struct mach_msg_file_status_send_t {
+    mach_msg_header_t header;
+    uint32_t version;
+    uint32_t command;
+    uint32_t status;
+};
+
+struct QtLaterDeleter {
+public:
+  void operator()(QObject *ptr) {
+    ptr->deleteLater();
+  }
+};
+} // anonymous namespace
+
+static NSString *const kFinderSyncMachPort = @"com.seafile.seafile-client.findersync.machport";
+// listener related
+static NSThread *finder_sync_listener_thread_ = nil;
+// atomic value
+static volatile int32_t finder_sync_started_ = 0;
+static FinderSyncListener *finder_sync_listener_ = nil;
+static std::unique_ptr<FinderSyncHost, QtLaterDeleter> finder_sync_host_;
+static constexpr uint32_t kFinderSyncProtocolVersion = 0x00000004;
+
+static void handleGetFileStatus(mach_msg_command_rcv_t* msg) {
+    // generate reply
+    mach_port_t port = msg->header.msgh_remote_port;
+    if (!port)
+        return;
+    mach_msg_file_status_send_t reply_msg;
+    bzero(&reply_msg, sizeof(mach_msg_header_t));
+    mach_msg_header_t *reply_msg_header =
+      reinterpret_cast<mach_msg_header_t*>(&reply_msg);
+    reply_msg_header->msgh_id = msg->header.msgh_id + 1;
+    reply_msg_header->msgh_size = sizeof(mach_msg_file_status_send_t);
+    reply_msg_header->msgh_local_port = MACH_PORT_NULL;
+    reply_msg_header->msgh_remote_port = port;
+    reply_msg_header->msgh_bits = MACH_MSGH_BITS_REMOTE(msg->header.msgh_bits);
+    reply_msg.status = finder_sync_host_->getFileStatus(msg->repo, msg->body);
+
+    // send the reply
+    kern_return_t kr = mach_msg_send(reply_msg_header);
+    if (kr != MACH_MSG_SUCCESS) {
+        qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+        // qWarning("[FinderSync] failed to send reply");
+    }
+
+    // destroy
+    mach_msg_destroy(reply_msg_header);
+}
+
+static void handleGetWatchSet(mach_msg_command_rcv_t* msg) {
+    // generate reply
+    mach_port_t port = msg->header.msgh_remote_port;
+    if (!port)
+        return;
+    utils::BufferArray reply_msg =
+      finder_sync_host_->getWatchSet(sizeof(mach_msg_header_t));
+    bzero(reply_msg.data(), sizeof(mach_msg_header_t));
+    mach_msg_header_t *reply_msg_header =
+      reinterpret_cast<mach_msg_header_t*>(reply_msg.data());
+    reply_msg_header->msgh_id = msg->header.msgh_id + 1;
+    reply_msg_header->msgh_size = reply_msg.size();
+    reply_msg_header->msgh_local_port = MACH_PORT_NULL;
+    reply_msg_header->msgh_remote_port = port;
+    reply_msg_header->msgh_bits = MACH_MSGH_BITS_REMOTE(msg->header.msgh_bits);
+
+    // send the reply
+    kern_return_t kr = mach_msg_send(reply_msg_header);
+    if (kr != MACH_MSG_SUCCESS) {
+        qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+        // qWarning("[FinderSync] failed to send reply");
+    }
+
+    // destroy
+    mach_msg_destroy(reply_msg_header);
+}
+
+@interface FinderSyncListener ()
+@property(readwrite, nonatomic, strong) NSPort *listenerPort;
+@end
+
+@implementation FinderSyncListener
+- (instancetype)init {
+    self = [super init];
+    self.listenerPort = nil;
+    return self;
+}
+- (void)start {
+    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
+    mach_port_t port = MACH_PORT_NULL;
+
+    kern_return_t kr =
+        mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
+    if (kr != KERN_SUCCESS) {
+        qWarning("[FinderSync] failed to allocate mach port");
+        qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+        kr = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE,
+                                -1);
+        if (kr != KERN_SUCCESS) {
+            qDebug("[FinderSync] failed to deallocate mach port");
+            qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+        }
+        return;
+    }
+
+    kr = mach_port_insert_right(mach_task_self(), port, port,
+                                MACH_MSG_TYPE_MAKE_SEND);
+    if (kr != KERN_SUCCESS) {
+        qWarning("[FinderSync] failed to insert send right to mach port");
+        qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+        kr = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE,
+                                -1);
+        if (kr != KERN_SUCCESS) {
+            qDebug("[FinderSync] failed to deallocate mach port");
+            qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+        }
+        qDebug("[FinderSync] failed to allocate send right tp local mach port");
+        return;
+    }
+    self.listenerPort =
+        [NSMachPort portWithMachPort:port
+                             options:NSMachPortDeallocateReceiveRight];
+    if (![[NSMachBootstrapServer sharedInstance]
+            registerPort:self.listenerPort
+                    name:kFinderSyncMachPort]) {
+        [self.listenerPort invalidate];
+        qWarning("[FinderSync] failed to register mach port");
+        qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+        return;
+    }
+    qDebug("[FinderSync] mach port registered");
+    [self.listenerPort setDelegate:self];
+    [runLoop addPort:self.listenerPort forMode:NSDefaultRunLoopMode];
+    while (finder_sync_started_)
+        [runLoop runMode:NSDefaultRunLoopMode
+              beforeDate:[NSDate distantFuture]];
+    [self.listenerPort invalidate];
+    qDebug("[FinderSync] mach port unregistered");
+    kr = mach_port_deallocate(mach_task_self(), port);
+    if (kr != KERN_SUCCESS) {
+        qDebug("[FinderSync] failed to deallocate mach port %u", port);
+        return;
+    }
+}
+- (void)stop {
+    CFRunLoopStop(CFRunLoopGetCurrent());
+}
+
+- (void)handleMachMessage:(void *)machMessage {
+    mach_msg_command_rcv_t *msg =
+        static_cast<mach_msg_command_rcv_t *>(machMessage);
+    if (msg->header.msgh_size != sizeof(mach_msg_command_send_t)) {
+        qWarning("[FinderSync] received msg with bad size %u", msg->header.msgh_size);
+        mach_msg_destroy(&msg->header);
+        return;
+    }
+
+    if (msg->version != kFinderSyncProtocolVersion) {
+        NSLog(@"FinderSync incompatible message protocol version %u", msg->version);
+        qWarning("[FinderSync] incompatible message protocol version %u", msg->version);
+        mach_msg_destroy(&msg->header);
+        // we need to quit before it cause more serious issue!
+        finderSyncListenerStop();
+        return;
+    }
+
+    switch (msg->command) {
+    case GetWatchSet:
+        handleGetWatchSet(msg);
+        break;
+    case DoShareLink:
+        // handle DoShareLink
+        QMetaObject::invokeMethod(finder_sync_host_.get(), "doShareLink",
+                                  Qt::QueuedConnection,
+                                  Q_ARG(QString, msg->body));
+        break;
+    case DoInternalLink:
+        // handle DoShareLink
+        QMetaObject::invokeMethod(finder_sync_host_.get(), "doInternalLink",
+                                  Qt::QueuedConnection,
+                                  Q_ARG(QString, msg->body));
+        break;
+    case DoGetFileStatus:
+        handleGetFileStatus(msg);
+        break;
+    case DoLockFile:
+        QMetaObject::invokeMethod(finder_sync_host_.get(), "doLockFile",
+                                  Qt::QueuedConnection,
+                                  Q_ARG(QString, msg->body),
+                                  Q_ARG(bool, true));
+        break;
+    case DoUnlockFile:
+        QMetaObject::invokeMethod(finder_sync_host_.get(), "doLockFile",
+                                  Qt::QueuedConnection,
+                                  Q_ARG(QString, msg->body),
+                                  Q_ARG(bool, false));
+        break;
+    case DoShowFileHistory:
+        QMetaObject::invokeMethod(finder_sync_host_.get(), "doShowFileHistory",
+                                  Qt::QueuedConnection,
+                                  Q_ARG(QString, msg->body));
+        break;
+    default:
+        qWarning("[FinderSync] received unknown command %u", msg->command);
+        break;
+    }
+    mach_msg_destroy(&msg->header);
+}
+
+@end
+
+void finderSyncListenerStart() {
+    if (!OSAtomicAdd32Barrier(0, &finder_sync_started_)) {
+        // this value is used in different threads
+        // keep it in atomic and guarenteed by barrier for safety
+        OSAtomicIncrement32Barrier(&finder_sync_started_);
+
+        dispatch_async(dispatch_get_main_queue(), ^{
+          finder_sync_host_.reset(new FinderSyncHost);
+          finder_sync_listener_ = [[FinderSyncListener alloc] init];
+          finder_sync_listener_thread_ =
+              [[NSThread alloc] initWithTarget:finder_sync_listener_
+                                      selector:@selector(start)
+                                        object:nil];
+          [finder_sync_listener_thread_ start];
+        });
+    }
+}
+
+void finderSyncListenerStop() {
+    if (OSAtomicAdd32Barrier(0, &finder_sync_started_)) {
+        // this value is used in different threads
+        // keep it in atomic and guarenteed by barrier for safety
+        OSAtomicDecrement32Barrier(&finder_sync_started_);
+
+        // tell finder_sync_listener_ to exit
+        [finder_sync_listener_ performSelector:@selector(stop)
+                                      onThread:finder_sync_listener_thread_
+                                    withObject:nil
+                                 waitUntilDone:NO];
+        dispatch_async(dispatch_get_main_queue(), ^{
+          finder_sync_host_.reset();
+        });
+    }
+}
diff --git a/src/finder-sync/finder-sync.cpp b/src/finder-sync/finder-sync.cpp
new file mode 100644 (file)
index 0000000..3bf9e39
--- /dev/null
@@ -0,0 +1,138 @@
+#include <QStringList>
+#include <QDir>
+#include <QFileInfo>
+#include <QProcess>
+#include <QDebug>
+#include "finder-sync/finder-sync.h"
+#include "utils/utils.h"
+#include "utils/utils-mac.h"
+
+static const char* kApplePluginkitBinary = "/usr/bin/pluginkit";
+static const char* kFinderSyncBundleIdentifier = "com.seafile.seafile-client.findersync";
+
+// run command and arugments,
+// and return the termination status
+// if we have non-null output, we will write stdout (not stderr) output to it
+static int runAsCommand(const QString &binary, const QStringList &arguments, QString
+                 *output = nullptr) {
+    QProcess process;
+    process.start(binary, arguments);
+    if (!process.waitForFinished(500))
+        return false;
+    if (output)
+        *output = process.readAllStandardOutput().trimmed();
+    return process.exitCode();
+}
+
+static inline QString pluginPath() {
+#ifdef XCODE_APP
+    return QDir(utils::mac::mainBundlePath()).filePath("Contents/PlugIns/Seafile FinderSync.appex");
+#else
+    return QDir(utils::mac::mainBundlePath()).filePath("fsplugin/Seafile FinderSync.appex");
+#endif
+}
+
+/// \brief list all installed plugins
+static bool installedPluginPath(QString *path) {
+    QStringList arguments {"-m", "-v", "-i", kFinderSyncBundleIdentifier};
+    int status = runAsCommand(kApplePluginkitBinary, arguments, path);
+    if (status != 0 || path->isEmpty())
+        return false;
+    int begin = path->indexOf('/');
+    if (begin == -1)
+        return false;
+    int end = path->indexOf('\n', begin);
+    if (end == -1 || end - begin < 0)
+        return false;
+    *path = QStringRef(path, begin, end - begin).toString();
+
+    qDebug("[FinderSync] found installed plugin %s", path->toUtf8().data());
+
+    return true;
+}
+
+bool FinderSyncExtensionHelper::isInstalled() {
+    QString output;
+    QStringList arguments {"-m", "-i", kFinderSyncBundleIdentifier};
+    int status = runAsCommand(kApplePluginkitBinary, arguments, &output);
+    if (status != 0 || output.isEmpty())
+        return false;
+
+    return true;
+}
+
+bool FinderSyncExtensionHelper::isEnabled() {
+    QString output;
+    QStringList arguments {"-m", "-i", kFinderSyncBundleIdentifier};
+    int status = runAsCommand(kApplePluginkitBinary, arguments, &output);
+    if (status != 0 || output.isEmpty())
+        return false;
+    if (output[0] != '+' && output[0] != '?')
+        return false;
+
+    return true;
+}
+
+bool FinderSyncExtensionHelper::isBundled() {
+    QString plugin_path = pluginPath();
+    if (!QFileInfo(plugin_path).isDir()) {
+        qDebug("[FinderSync] unable to find bundled plugin at %s", plugin_path.toUtf8().data());
+        return false;
+    }
+
+    qDebug("[FinderSync] found bundled plugin at %s", plugin_path.toUtf8().data());
+    return true;
+}
+
+// Developer notes:
+//  In Mac OSX Sierra and higher, to install a finder plugin (a .appex folder) ,
+//  two conditions must be satisfied:
+//    - the plugin must be signed
+//    - the plugin must be included as part of a .app
+//  So when seadrive-gui is not compiled with xcode, there is no way to install
+//  the plugin.
+#ifdef XCODE_APP
+bool FinderSyncExtensionHelper::reinstall(bool force) {
+    if (!isBundled())
+        return false;
+
+    QString bundled_plugin_path = pluginPath();
+    QString plugin_path;
+    QStringList remove_arguments;
+
+    // remove all installed plugins
+    while(installedPluginPath(&plugin_path)) {
+        if (!force && bundled_plugin_path == plugin_path) {
+            qDebug("[FinderSync] current plugin detected: %s",
+                   bundled_plugin_path.toUtf8().data());
+            return true;
+        }
+        remove_arguments = QStringList {"-r", plugin_path};
+        // this command returns non-zero when succeeds,
+        // so don't bother to check it
+        runAsCommand(kApplePluginkitBinary, remove_arguments);
+    }
+
+    QStringList install_arguments {"-a", bundled_plugin_path};
+    int status = runAsCommand(kApplePluginkitBinary, install_arguments);
+    if (status != 0)
+        return false;
+
+    qWarning("[FinderSync] reinstalled");
+    return true;
+}
+#else
+bool FinderSyncExtensionHelper::reinstall(bool force) {
+    return false;
+}
+#endif
+
+bool FinderSyncExtensionHelper::setEnable(bool enable) {
+    const char *election = enable ? "use" : "ignore";
+    QStringList arguments {"-e", election, "-i", kFinderSyncBundleIdentifier};
+    int status = runAsCommand(kApplePluginkitBinary, arguments);
+    if (status != 0)
+        return false;
+
+    return true;
+}
diff --git a/src/finder-sync/finder-sync.h b/src/finder-sync/finder-sync.h
new file mode 100644 (file)
index 0000000..15d91b5
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef SEAFILE_CLIENT_FINDER_SYNC_H_
+#define SEAFILE_CLIENT_FINDER_SYNC_H_
+
+class FinderSyncExtensionHelper {
+public:
+    /// \brief check if plugin is installed
+    /// return true if installed
+    ///
+    static bool isInstalled();
+
+    /// \brief check if plugin is enabled
+    /// return true if enabled
+    /// this value can be changed via preference by user
+    static bool isEnabled();
+
+    /// \brief check if plugin has been bundled
+    /// return true if bundled
+    ///
+    static bool isBundled();
+
+    /// \brief do reinstall for the bundled plugin
+    /// return true if success
+    ///
+    static bool reinstall(bool force = false);
+
+    /// \brief change the plugin's status
+    /// return ture if success
+    ///
+    static bool setEnable(bool enable);
+};
+
+#endif // SEAFILE_CLIENT_FINDER_SYNC_H_
diff --git a/src/i18n.cpp b/src/i18n.cpp
new file mode 100644 (file)
index 0000000..80036bf
--- /dev/null
@@ -0,0 +1,161 @@
+#include <glib.h>
+#include <QTranslator>
+#include <QLibraryInfo>
+#include <QApplication>
+#include <QSettings>
+#include <QDebug>
+
+#include "i18n.h"
+
+namespace {
+const char* langs[] = {
+    NULL, //reserved for system locale
+    "ca",
+    "de_DE",
+    "en",
+    "es",
+    "es_AR",
+    "es_MX",
+    "fr_FR",
+    "he_IL",
+    "hu_HU",
+    "is",
+    "it",
+    "ko_KR",
+    "nl_BE",
+    "pl_PL",
+    "pt_BR",
+    "pt_PT",
+    "ru",
+    "sk_SK",
+    "uk",
+    "zh_CN",
+    "zh_TW",
+    "tr",
+    "nl_NL",
+    "lv",
+    "ja",
+    "sv",
+    "cs_CZ",
+    "el_GR",
+    "nb_NO",
+    NULL
+    };
+void saveCurrentLanguage(int langIndex) {
+    QSettings settings;
+
+    settings.beginGroup("Language");
+    settings.setValue("current", QString(langs[langIndex]));
+    settings.endGroup();
+}
+
+int loadCurrentLanguage() {
+    QSettings settings;
+
+    settings.beginGroup("Language");
+    QString current = settings.value("current").toString();
+    settings.endGroup();
+
+    // system locale
+    if (current.isEmpty()) {
+        return 0;
+    }
+
+    const char** pos = langs; /* skip first one*/
+    while(*++pos != NULL) {
+        if (*pos == current)
+            break;
+    }
+    return pos - langs;
+}
+
+} // anonymous namespace
+
+I18NHelper *I18NHelper::instance_ = NULL;
+
+I18NHelper::I18NHelper()
+    : qt_translator_(new QTranslator),
+      my_translator_(new QTranslator)
+{
+}
+
+I18NHelper::~I18NHelper() {
+}
+
+void I18NHelper::init() {
+    qApp->installTranslator(qt_translator_.data());
+    qApp->installTranslator(my_translator_.data());
+    int pos = preferredLanguage();
+    if (langs[pos] == NULL) // NULL is reserved for system locale
+        setLanguage(0);
+    else
+        setLanguage(pos);
+}
+
+int I18NHelper::preferredLanguage() {
+    return loadCurrentLanguage();
+}
+
+void I18NHelper::setPreferredLanguage(int langIndex) {
+    const QList<QLocale> &locales = getInstalledLocales();
+    if (langIndex < 0 || langIndex >= locales.size())
+        return;
+    saveCurrentLanguage(langIndex);
+}
+
+bool I18NHelper::setLanguage(int langIndex) {
+    const QList<QLocale> &locales = getInstalledLocales();
+    if (langIndex < 0 || langIndex >= locales.size())
+        return false;
+
+    const QLocale &locale = locales[langIndex];
+#if defined(Q_OS_WIN32)
+    qt_translator_->load("qt_" + locale.name());
+#else
+    qt_translator_->load("qt_" + locale.name(),
+                      QLibraryInfo::location(QLibraryInfo::TranslationsPath));
+#endif
+
+    QString lang = QLocale::languageToString(locale.language());
+    printf("lang = %s, translation = %s, locale.name() = %s\n",
+           lang.toUtf8().data(),
+           langs[langIndex],
+           locale.name().toUtf8().data()
+        );
+    if (lang != "English") {
+        if (!my_translator_->load(locale, ":/i18n/seafile_")) {
+            printf ("failed to load in the first way\n");
+            my_translator_->load(
+                QString(":/i18n/seafile_%1.qm").arg(locale.name()));
+        }
+    }
+
+    return true;
+}
+
+const QList<QLocale> &I18NHelper::getInstalledLocales() {
+    static QList<QLocale> locales;
+    if (locales.empty()) {
+        locales.push_back(QLocale::system());
+        const char** next = langs; /* skip the first one*/
+        while(*++next != NULL)
+            locales.push_back(QLocale(*next));
+    }
+    return locales;
+}
+
+bool I18NHelper::isChinese()
+{
+    int lang_index = preferredLanguage();
+    if (lang_index < 0 || lang_index >= (int)G_N_ELEMENTS(langs))
+        return false;
+
+    if (lang_index == 0) {
+        // An index of 0 means seafile client is configured to use the system locale.
+        QLocale sys_locale = QLocale::system();
+        return sys_locale.country() == QLocale::China;
+    } else {
+        QString lang = QString(langs[lang_index]);
+        return lang == "zh_CN";
+    }
+}
diff --git a/src/i18n.h b/src/i18n.h
new file mode 100644 (file)
index 0000000..ac37ffd
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _SEAF_I18N_H
+#define _SEAF_I18N_H
+#include <QList>
+#include <QLocale>
+#include <QStringList>
+#include <QScopedPointer>
+
+class QTranslator;
+class I18NHelper {
+public:
+    static I18NHelper* getInstance() {
+      if (!instance_) {
+          static I18NHelper i18n;
+          instance_ = &i18n;
+      }
+      return instance_;
+    }
+
+    void init();
+
+    QStringList getLanguages() {
+        QStringList languages;
+        Q_FOREACH(const QLocale& locale, getInstalledLocales())
+        {
+            languages.push_back(
+                QString("%1 - %2").arg(QLocale::languageToString(locale.language()))
+                                  .arg(QLocale::countryToString(locale.country())));
+        }
+        languages.front() = "-- System --";
+        return languages;
+    }
+
+    bool isChinese();
+    int preferredLanguage();
+    void setPreferredLanguage(int langIndex);
+private:
+    I18NHelper();
+    ~I18NHelper();
+    I18NHelper(const I18NHelper&); // = delete
+
+    const QList<QLocale> &getInstalledLocales();
+    bool setLanguage(int langIndex);
+    QScopedPointer<QTranslator> qt_translator_;
+    QScopedPointer<QTranslator> my_translator_;
+
+    static I18NHelper *instance_;
+};
+
+
+#endif // _SEAF_I18N_H
diff --git a/src/log-uploader.cpp b/src/log-uploader.cpp
new file mode 100644 (file)
index 0000000..0aa99a7
--- /dev/null
@@ -0,0 +1,225 @@
+
+#include <QtGlobal>
+
+#include <QSysInfo>
+#include <QThreadPool>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "account-mgr.h"
+
+#include "log-uploader.h"
+#include "JlCompress.h"
+#include "api/requests.h"
+
+namespace {
+
+const char* kGetUploadFileLink = "http://192.168.1.113:8000/api/v2.1/upload-links/dcfa5dd6645e4f38b823/upload/";
+const QString getLogUploadLink()
+{
+    QString upload_link = qgetenv("SEAFILE_LOG_UPLOAD_LINK");
+    return !upload_link.isEmpty() ? upload_link : kGetUploadFileLink;
+}
+
+} // namespace
+
+
+LogDirUploader::LogDirUploader()
+    : task_(nullptr)
+{
+}
+
+LogDirUploader::~LogDirUploader()
+{
+    if (task_) {
+        task_->deleteLater();
+        task_ = nullptr;
+    }
+}
+
+void LogDirUploader::start()
+{
+    progress_dlg_ = new LogUploadProgressDialog();
+    connect(progress_dlg_, SIGNAL(canceled()),
+            this, SLOT(onCanceled()));
+
+    LogDirCompressor *uploader = new LogDirCompressor;
+    connect(uploader, SIGNAL(compressFinished(bool, const QString&)),
+            this, SLOT(onCompressFinished(bool, const QString&)));
+    uploader->setAutoDelete(true);
+    QThreadPool::globalInstance()->start(uploader);
+}
+
+void LogDirUploader::onFinished()
+{
+    deleteLater();
+    if (progress_dlg_) {
+        progress_dlg_->accept();
+        progress_dlg_ = nullptr;
+    }
+}
+
+void LogDirUploader::onCanceled()
+{
+    if (task_) {
+        task_->cancel();
+    }
+    progress_dlg_ = nullptr;
+    if (QFile::exists(compressed_file_name_)) {
+        QFile::remove(compressed_file_name_);
+    }
+    onFinished();
+    emit finished();
+}
+
+void LogDirUploader::onCompressFinished(bool success, const QString& compressed_file_name)
+{
+    compressed_file_name_ = compressed_file_name;
+    if (success) {
+        SeafileApiRequest * get_upload_link_req = new GetUploadFileLinkRequest(getLogUploadLink());
+        connect(get_upload_link_req, SIGNAL(success(const QString&)),
+                this, SLOT(onGetUploadLinkSuccess(const QString&)));
+        connect(get_upload_link_req, SIGNAL(failed(const ApiError&)),
+                this, SLOT(onGetUploadLinkFailed(const ApiError&)));
+        get_upload_link_req->send();
+    } else {
+        seafApplet->warningBox(tr("Upload log files failed"));
+        onFinished();
+    }
+}
+
+void LogDirUploader::onGetUploadLinkSuccess(const QString& upload_link)
+{
+    if (progress_dlg_ == nullptr) {
+        if (QFile::exists(compressed_file_name_)) {
+            QFile::remove(compressed_file_name_);
+        }
+        return;
+    }
+    progress_dlg_->setWindowTitle(tr("Upload log files"));
+    QFile *file = new QFile(compressed_file_name_);
+    if (!file->exists()) {
+        qWarning("Upload %s failed. File does not exist.", toCStr(compressed_file_name_));
+        return;
+    }
+    if (!file->open(QIODevice::ReadOnly)) {
+        qWarning("Upload %s failed. Couldn't open file.", toCStr(compressed_file_name_));
+        return;
+    }
+    QString file_name = getBaseName(compressed_file_name_);
+    task_ = new PostFileTask(QUrl(upload_link), QString("/"),
+                                           compressed_file_name_, file, file_name, QString(), 0);
+    connect(task_, SIGNAL(finished(bool)), this, SLOT(onUploadLogDirFinished(bool)));
+    connect(task_, SIGNAL(progressUpdate(qint64, qint64)),
+            this, SLOT(onProgressUpdate(qint64, qint64)));
+
+    task_->start();
+}
+
+void LogDirUploader::onGetUploadLinkFailed(const ApiError &)
+{
+    qWarning("Get upload link failed.");
+    seafApplet->warningBox(tr("Upload log files failed"));
+    onFinished();
+}
+
+void LogDirUploader::onProgressUpdate(qint64 processed_bytes, qint64 total_bytes)
+{
+    if (total_bytes == 0) {
+        return;
+    }
+    if (task_->canceled()) {
+        return;
+    }
+    progress_dlg_->updateData(processed_bytes, total_bytes);
+}
+
+void LogDirUploader::onUploadLogDirFinished(bool success)
+{
+    if (task_->canceled()) {
+        return;
+    }
+
+    if (progress_dlg_) {
+        progress_dlg_ = nullptr;
+    }
+
+    if (!success) {
+        QString _error;
+        if (task_->httpErrorCode() == 403) {
+            _error = tr("Permission Error!");
+        } else if (task_->httpErrorCode() == 404) {
+            _error = tr("Library/Folder not found.");
+        } else if (task_->httpErrorCode() == 401) {
+            _error = tr("Authorization expired");
+        } else {
+            _error = task_->errorString();
+        }
+        QString msg = tr("Upload log files failed :%1").arg(_error);
+        seafApplet->warningBox(msg);
+    } else {
+
+        if (QFile::exists(compressed_file_name_)) {
+            QFile::remove(compressed_file_name_);
+        }
+        seafApplet->messageBox(tr("Successfully uploaded log files"));
+    }
+    onFinished();
+    emit finished();
+}
+
+LogUploadProgressDialog::LogUploadProgressDialog(QWidget *parent)
+        : QProgressDialog(parent)
+{
+    // set dialog attributes
+    setAttribute(Qt::WA_DeleteOnClose);
+    setWindowModality(Qt::NonModal);
+    setWindowTitle(tr("Compressing"));
+    setCancelButtonText(tr("Cancel"));
+    show();
+    raise();
+    activateWindow();
+}
+
+LogUploadProgressDialog::~LogUploadProgressDialog()
+{
+}
+
+void LogUploadProgressDialog::updateData(qint64 processed_bytes, qint64 total_bytes)
+{
+    if (total_bytes > INT_MAX) {
+        if (maximum() != INT_MAX) {
+            setMaximum(INT_MAX);
+        }
+
+        // Avoid overflow
+        double progress = double(processed_bytes) * INT_MAX / total_bytes;
+        setValue((int)progress);
+    } else {
+        if (maximum() != total_bytes) {
+            setMaximum(total_bytes);
+        }
+
+        setValue(processed_bytes);
+    }
+
+    setLabelText(tr("%1 of %2")
+        .arg(::readableFileSizeV2(processed_bytes))
+        .arg(::readableFileSizeV2(total_bytes)));
+}
+
+void LogDirCompressor::run() {
+    QString log_path = QDir(seafApplet->configurator()->ccnetDir()).absoluteFilePath("logs");
+    QString username = seafApplet->accountManager()->currentAccount().username;
+    QString time = QDateTime::currentDateTime().toString("yyyy.MM.dd-hh.mm.ss");
+    compressed_file_name_ = log_path + '-' + time + '-' + username + ".zip";
+
+    if (!JlCompress::compressDir(compressed_file_name_, log_path)) {
+        qWarning("create log archive failed");
+        emit compressFinished(false);
+    } else {
+        emit compressFinished(true, compressed_file_name_);
+    }
+}
diff --git a/src/log-uploader.h b/src/log-uploader.h
new file mode 100644 (file)
index 0000000..bcd5628
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef SEAFILE_CLIENT_LOG_UPLOADER_H
+#define SEAFILE_CLIENT_LOG_UPLOADER_H
+
+#include <QObject>
+#include <QRunnable>
+#include <QProgressDialog>
+#include "account.h"
+#include "filebrowser/reliable-upload.h"
+
+class LogUploadProgressDialog;
+class LogDirUploader : public QObject {
+    Q_OBJECT
+public:
+    LogDirUploader();
+    ~LogDirUploader();
+signals:
+    void finished();
+public slots:
+    virtual void start();
+private slots:
+    void onCanceled();
+    void onCompressFinished(bool success, const QString& compressed_file_name);
+    void onGetUploadLinkSuccess(const QString&);
+    void onGetUploadLinkFailed(const ApiError&);
+    void onUploadLogDirFinished(bool success);
+    void onProgressUpdate(qint64 processed_bytes, qint64 total_bytes);
+private:
+    void onFinished();
+    QString compressed_file_name_;
+    PostFileTask *task_;
+    LogUploadProgressDialog *progress_dlg_;
+};
+
+class LogUploadProgressDialog : public QProgressDialog {
+    Q_OBJECT
+public:
+    LogUploadProgressDialog(QWidget *parent=0);
+    ~LogUploadProgressDialog();
+    void updateData(qint64 processed_bytes, qint64 total_bytes);
+};
+
+
+class LogDirCompressor : public QObject, public QRunnable {
+    Q_OBJECT
+public:
+    LogDirCompressor() {};
+
+signals:
+    void compressFinished(bool success,
+                          const QString& compressed_file_name = QString());
+
+public slots:
+    void run();
+
+private:
+    QString compressed_file_name_;
+    QProgressDialog *progress_dlg_;
+};
+#endif // SEAFILE_CLIENT_LOG_UPLOADER_H
diff --git a/src/mac-sparkle-support.h b/src/mac-sparkle-support.h
new file mode 100644 (file)
index 0000000..09dfd6f
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SEAFILE_CLIENT_SPARKLE_SUPPORT_H
+#define SEAFILE_CLIENT_SPARKLE_SUPPORT_H
+
+class SparkleHelper {
+public:
+    static void checkForUpdate();
+    static void setAutoUpdateEnabled(bool enabled);
+    static bool autoUpdateEnabled();
+    static void setFeedURL(const char* url);
+};
+
+#endif // SEAFILE_CLIENT_SPARKLE_SUPPORT_H
diff --git a/src/mac-sparkle-support.mm b/src/mac-sparkle-support.mm
new file mode 100644 (file)
index 0000000..ecb3cf3
--- /dev/null
@@ -0,0 +1,27 @@
+#include "mac-sparkle-support.h"
+
+#import "SUUpdater.h"
+
+void SparkleHelper::checkForUpdate()
+{
+    // [[SUUpdater sharedUpdater] checkForUpdatesInBackground];
+    [[SUUpdater sharedUpdater] checkForUpdates:nil];
+}
+
+void SparkleHelper::setAutoUpdateEnabled(bool enabled)
+{
+    [[SUUpdater sharedUpdater] setAutomaticallyChecksForUpdates: enabled];
+    // [[SUUpdater sharedUpdater] setAutomaticallyDownloadsUpdates: enabled];
+}
+
+void SparkleHelper::setFeedURL(const char* url)
+{
+    NSString *nsstr = [NSString stringWithCString:url
+                                  encoding:NSUTF8StringEncoding];
+    NSURL *feedURL = [NSURL URLWithString:nsstr];
+    [[SUUpdater sharedUpdater] setFeedURL: feedURL];
+}
+
+bool SparkleHelper::autoUpdateEnabled() {
+    return [[SUUpdater sharedUpdater] automaticallyChecksForUpdates];
+}
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..58376be
--- /dev/null
@@ -0,0 +1,228 @@
+#include <getopt.h>
+#include <QApplication>
+#include <QMessageBox>
+#include <QWidget>
+#include <QDir>
+
+#include <glib-object.h>
+#include <cstdio>
+
+#include "i18n.h"
+#include "crash-handler.h"
+#include "utils/utils.h"
+#include "utils/paint-utils.h"
+#include "utils/process.h"
+#include "utils/uninstall-helpers.h"
+#include "ui/proxy-style.h"
+#include "seafile-applet.h"
+#include "QtAwesome.h"
+#include "open-local-helper.h"
+#if defined(Q_OS_WIN32)
+#include "utils/utils-win.h"
+#endif
+#if defined(Q_OS_MAC)
+#include "application.h"
+#endif
+
+#define APPNAME "seafile-applet"
+
+namespace {
+void initGlib()
+{
+#if !GLIB_CHECK_VERSION(2, 35, 0)
+    g_type_init();
+#endif
+#if !GLIB_CHECK_VERSION(2, 31, 0)
+    g_thread_init(NULL);
+#endif
+}
+
+void initBreakpad()
+{
+#ifdef SEAFILE_CLIENT_HAS_CRASH_REPORTER
+    // if we have built with breakpad, load it in run time
+    Breakpad::CrashHandler::instance()->Init(
+        QDir(defaultCcnetDir()).absoluteFilePath("crash-applet"));
+#endif
+}
+
+void setupFontFix()
+{
+#if QT_VERSION < QT_VERSION_CHECK(5, 3, 2) && defined(Q_OS_MAC)
+    // Text in buttons and drop-downs looks misaligned in osx 10.10,
+    // fixed in qt5.3.2
+    // https://bugreports.qt-project.org/browse/QTBUG-40833
+    if ( QSysInfo::MacintoshVersion > QSysInfo::MV_10_8 ) {
+        QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Helvetica Neue");
+    }
+#endif // QT_VERSION_CHECK(5, 3, 2)
+}
+
+void setupHIDPIFix()
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
+    // enable builtin retina mode
+    // http://blog.qt.digia.com/blog/2013/04/25/retina-display-support-for-mac-os-ios-and-x11/
+    // https://qt.gitorious.org/qt/qtbase/source/a3cb057c3d5c9ed2c12fb7542065c3d667be38b7:src/gui/image/qicon.cpp#L1028-1043
+    qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);
+#endif
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
+  #if defined(Q_OS_WIN32)
+    if (!utils::win::fixQtHDPINonIntegerScaling()) {
+        qApp->setAttribute(Qt::AA_EnableHighDpiScaling);
+    }
+  #elif !defined(Q_OS_MAC)
+    // Enable HDPI auto detection.
+    // See http://blog.qt.io/blog/2016/01/26/high-dpi-support-in-qt-5-6/
+    qApp->setAttribute(Qt::AA_EnableHighDpiScaling);
+  #endif
+#endif
+}
+
+void setupSettingDomain()
+{
+    // see QSettings documentation
+    QCoreApplication::setOrganizationName(getBrand());
+    QCoreApplication::setOrganizationDomain("seafile.com");
+    QCoreApplication::setApplicationName(QString("%1 Client").arg(getBrand()));
+}
+
+void handleCommandLineOption(int argc, char *argv[])
+{
+    int c;
+    static const char *short_options = "KDXPc:d:f:";
+    static const struct option long_options[] = {
+        { "config-dir", required_argument, NULL, 'c' },
+        { "data-dir", required_argument, NULL, 'd' },
+        { "stop", no_argument, NULL, 'K' },
+        { "delay", no_argument, NULL, 'D' },
+        { "remove-user-data", no_argument, NULL, 'X' },
+        { "open-local-file", no_argument, NULL, 'f' },
+        { "stdout", no_argument, NULL, 'l' },
+        { "ping", no_argument, NULL, 'P' },
+        { NULL, 0, NULL, 0, },
+    };
+
+    while ((c = getopt_long (argc, argv, short_options,
+                             long_options, NULL)) != EOF) {
+        switch (c) {
+        case 'c':
+            g_setenv ("CCNET_CONF_DIR", optarg, 1);
+            break;
+        case 'd':
+            g_setenv ("SEAFILE_DATA_DIR", optarg, 1);
+            break;
+        case 'l':
+            g_setenv ("LOG_STDOUT", "", 1);
+            break;
+        case 'K':
+            do_stop();
+            exit(0);
+        case 'P':
+            do_ping();
+            exit(0);
+        case 'D':
+            msleep(1000);
+            break;
+        case 'X':
+            do_remove_user_data();
+            exit(0);
+        case 'f':
+            OpenLocalHelper::instance()->handleOpenLocalFromCommandLine(optarg);
+            break;
+#if defined(HAVE_SPARKLE_SUPPORT) && defined(WINSPARKLE_DEBUG)
+        case 'U':
+            g_setenv ("SEAFILE_CLIENT_APPCAST_URI", optarg, 1);
+            break;
+#endif
+        default:
+            exit(1);
+        }
+    }
+
+}
+
+} // anonymous namespace
+
+int main(int argc, char *argv[])
+{
+    int ret = 0;
+
+    // call glib's init functions
+    initGlib();
+
+    // initialize breakpad if enabled
+    initBreakpad();
+
+    // Apply hidpi support
+    setupHIDPIFix();
+
+#if defined(Q_OS_WIN32)
+    // When the user start seafile applet from the windows "Start" menu, the
+    // working directory is set to the parent folder of the seafile-applet.exe.
+    // See https://github.com/haiwen/seafile/blob/v6.0.1/msi/seafile.wxs#L60
+    //
+    // Sometimes the seafile-applet program would abort with error messgages
+    // "can't find qt plugin windows dll". So here we add current directory to
+    // the library path, hopefully fixing that problem.
+    QCoreApplication::addLibraryPath(".\\");
+#endif
+
+    // TODO imple if we have to restart the application
+    // the manual at http://qt-project.org/wiki/ApplicationRestart
+#if defined(Q_OS_MAC)
+    Application app(argc, argv);
+#else
+    QApplication app(argc, argv);
+#endif
+
+    // don't quit even if the last windows is closed
+    app.setQuitOnLastWindowClosed(false);
+
+    // apply some ui fixes for mac
+    setupFontFix();
+
+    // set the domains of settings
+    setupSettingDomain();
+
+    // initialize i18n settings
+    I18NHelper::getInstance()->init();
+
+    // initialize style settings
+    app.setStyle(new SeafileProxyStyle());
+
+    // start applet
+    SeafileApplet mApplet;
+    seafApplet = &mApplet;
+
+    // handle with the command arguments
+    handleCommandLineOption(argc, argv);
+
+    // count if we have any instance running now. if more than one, exit
+    if (count_process(APPNAME) > 1) {
+        if (OpenLocalHelper::instance()->activateRunningInstance()) {
+            printf("Activated running instance of seafile client\n");
+            return 0;
+        }
+        QMessageBox::warning(NULL, getBrand(),
+                             QObject::tr("%1 Client is already running").arg(getBrand()),
+                             QMessageBox::Ok);
+        return -1;
+    }
+
+    // init qtawesome component
+    awesome = new QtAwesome(qApp);
+    awesome->initFontAwesome();
+
+    seafApplet->start();
+
+    // qWarning("globalDevicePixelRatio() = %f\n", globalDevicePixelRatio());
+    // printf("globalDevicePixelRatio() = %f\n", globalDevicePixelRatio());
+    // fflush(stdout);
+
+    // start qt eventloop
+    ret = app.exec();
+
+    return ret;
+}
diff --git a/src/message-poller.cpp b/src/message-poller.cpp
new file mode 100644 (file)
index 0000000..862335f
--- /dev/null
@@ -0,0 +1,228 @@
+#include <QTimer>
+#include <QDateTime>
+
+#include "utils/utils.h"
+#include "utils/translate-commit-desc.h"
+#include "utils/json-utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "daemon-mgr.h"
+#include "settings-mgr.h"
+#include "rpc/rpc-client.h"
+#include "rpc/sync-error.h"
+#include "ui/tray-icon.h"
+
+#include "message-poller.h"
+
+namespace {
+
+const int kCheckNotificationIntervalMSecs = 1000;
+
+} // namespace
+
+#define SYNC_ERROR_ID_FILE_LOCKED_BY_APP 0
+#define SYNC_ERROR_ID_FOLDER_LOCKED_BY_APP 1
+#define SYNC_ERROR_ID_FILE_LOCKED 2
+#define SYNC_ERROR_ID_INVALID_PATH 3
+#define SYNC_ERROR_ID_INDEX_ERROR 4
+#define SYNC_ERROR_ID_END_SPACE_PERIOD 5
+#define SYNC_ERROR_ID_INVALID_CHARACTER 6
+#define SYNC_ERROR_ID_FOLDER_PERM_DENIED 7
+#define SYNC_ERROR_ID_PERM_NOT_SYNCABLE 8
+#define SYNC_ERROR_ID_UPDATE_TO_READ_ONLY_REPO 9
+
+struct SyncNotification {
+    QString type;
+    QString content;
+
+    static SyncNotification fromJson(const json_t* json);
+};
+
+
+MessagePoller::MessagePoller(QObject *parent): QObject(parent)
+{
+    rpc_client_ = new SeafileRpcClient();
+    check_notification_timer_ = new QTimer(this);
+    connect(check_notification_timer_, SIGNAL(timeout()), this, SLOT(checkNotification()));
+}
+
+MessagePoller::~MessagePoller()
+{
+    delete check_notification_timer_;
+    delete rpc_client_;
+}
+
+void MessagePoller::start()
+{
+    rpc_client_->tryConnectDaemon();
+    check_notification_timer_->start(kCheckNotificationIntervalMSecs);
+    connect(seafApplet->daemonManager(), SIGNAL(daemonDead()), this, SLOT(onDaemonDead()));
+    connect(seafApplet->daemonManager(), SIGNAL(daemonRestarted()), this, SLOT(onDaemonRestarted()));
+}
+
+void MessagePoller::onDaemonDead()
+{
+    qDebug("pausing message poller when daemon is dead");
+    check_notification_timer_->stop();
+}
+
+void MessagePoller::onDaemonRestarted()
+{
+    qDebug("reviving message poller when daemon is restarted");
+    if (rpc_client_) {
+        delete rpc_client_;
+    }
+    rpc_client_ = new SeafileRpcClient();
+    rpc_client_->tryConnectDaemon();
+    check_notification_timer_->start(kCheckNotificationIntervalMSecs);
+}
+
+void MessagePoller::checkNotification()
+{
+    json_t *ret;
+    if (!rpc_client_->getSyncNotification(&ret)) {
+        return;
+    }
+    SyncNotification notification = SyncNotification::fromJson(ret);
+    json_decref(ret);
+
+    processNotification(notification);
+}
+
+SyncNotification SyncNotification::fromJson(const json_t *root)
+{
+    SyncNotification notification;
+    Json json(root);
+
+    // char *s = json_dumps(root, 0);
+    // printf ("[%s] %s\n", QDateTime::currentDateTime().toString().toUtf8().data(), s);
+    // qWarning ("[%s] %s\n", QDateTime::currentDateTime().toString().toUtf8().data(), s);
+    // free (s);
+
+    notification.type = json.getString("type");
+    notification.content = json.getString("content");
+    return notification;
+}
+
+void MessagePoller::processNotification(const SyncNotification& notification)
+{
+    const QString& type = notification.type;
+    const QString& content = notification.content;
+    if (type == "transfer") {
+        // empty
+    } else if (type == "repo.deleted_on_relay") {
+        QString buf = tr("\"%1\" is unsynced. \nReason: Deleted on server").arg(content);
+        seafApplet->trayIcon()->showMessage(getBrand(), buf);
+    } else if (type == "sync.done" ||
+               type == "sync.multipart_upload") {
+        /* format: a concatenation of (repo_name, repo_id, commmit_id,
+         * previous_commit_id, description), separated by tabs */
+        QStringList slist = content.split("\t");
+        if (slist.count() != 5) {
+            qWarning("Bad sync.done message format");
+            return;
+        }
+
+        QString title;
+        if (type == "sync.done")
+            title = tr("\"%1\" is synchronized").arg(slist.at(0));
+        else
+            title = tr("Files uploaded to \"%1\"").arg(slist.at(0));
+        QString repo_id = slist.at(1).trimmed();
+        QString commit_id = slist.at(2).trimmed();
+        QString previous_commit_id = slist.at(3).trimmed();
+        QString desc = slist.at(4).trimmed();
+
+        seafApplet->trayIcon()->showMessage(title, translateCommitDesc(desc), repo_id, commit_id, previous_commit_id);
+
+    } else if (type == "sync.conflict") {
+        json_error_t error;
+        json_t *object = json_loads(toCStr(content), 0, &error);
+        if (!object) {
+            qWarning("Failed to parse json: %s", error.text);
+            return;
+        }
+
+        QString repo_id = QString::fromUtf8(json_string_value(json_object_get(object, "repo_id")));
+        QString title = QString::fromUtf8(json_string_value(json_object_get(object, "repo_name")));
+        QString path = QString::fromUtf8(json_string_value(json_object_get(object, "path")));
+        QString msg = tr("File %1 conflict").arg(path);
+
+        seafApplet->trayIcon()->showMessage(title, msg, repo_id);
+
+        json_decref(object);
+    } else if (type == "sync.error") {
+        json_error_t error;
+        json_t *object = json_loads(toCStr(content), 0, &error);
+        if (!object) {
+            qWarning("Failed to parse json: %s", error.text);
+            return;
+        }
+
+        QString repo_id = QString::fromUtf8(json_string_value(json_object_get(object, "repo_id")));
+        QString title = QString::fromUtf8(json_string_value(json_object_get(object, "repo_name")));
+        QString path = QString::fromUtf8(json_string_value(json_object_get(object, "path")));
+        int err_id = json_integer_value(json_object_get(object, "err_id"));
+        QString msg;
+        switch (err_id) {
+        case SYNC_ERROR_ID_FILE_LOCKED_BY_APP:
+            msg = tr("Failed to sync file %1\nFile is locked by other application. This file will be updated when you close the application.").arg(path);
+            break;
+        case SYNC_ERROR_ID_FOLDER_LOCKED_BY_APP:
+            msg = tr("Failed to sync folder %1\nSome file in this folder is locked by other application. This folder will be updated when you close the application.").arg(path);
+            break;
+        case SYNC_ERROR_ID_FILE_LOCKED:
+            msg = tr("Failed to sync file %1\nFile is locked by another user. Update to this file is not uploaded.").arg(path);
+            break;
+            // case SYNC_ERROR_ID_INVALID_PATH:
+            //     msg = tr("Failed to sync %1\nFile path contains invalid characters. It is not synced to this computer.").arg(path);
+            //     break;
+        case SYNC_ERROR_ID_INDEX_ERROR:
+            msg = tr("Failed to index file %1\nPlease check file permission and disk space.").arg(path);
+            break;
+        case SYNC_ERROR_ID_END_SPACE_PERIOD:
+            msg = tr("Failed to sync %1\nFile path is ended with space or period and cannot be created on Windows.").arg(path);
+            break;
+        case SYNC_ERROR_ID_INVALID_CHARACTER:
+            msg = tr("Failed to sync %1\nFile path contains invalid characters. It is not synced to this computer.").arg(path);
+            break;
+        case SYNC_ERROR_ID_FOLDER_PERM_DENIED:
+            msg = tr("Update to file %1 is denied by folder permission setting.").arg(path);
+            break;
+        case SYNC_ERROR_ID_PERM_NOT_SYNCABLE:
+            msg = tr("No permission to sync folder %1.").arg(path);
+            break;
+        case SYNC_ERROR_ID_UPDATE_TO_READ_ONLY_REPO:
+            msg = tr("Updates in read-only library will not be uploaded.");
+            break;
+        default:
+            qWarning("Unknown sync error id %d", err_id);
+            json_decref(object);
+            return;
+        }
+
+        seafApplet->trayIcon()->showMessage(title, msg, repo_id);
+
+        json_decref(object);
+    } else if (type == "sync.access_denied") {
+        /* format: <repo_name\trepo_id> */
+        QStringList slist = content.split("\t");
+        if (slist.count() != 2) {
+            qWarning("Bad sync.access_denied message format");
+            return;
+        }
+        QString buf = tr("\"%1\" failed to sync. \nAccess denied to service").arg(slist.at(0));
+        seafApplet->trayIcon()->showMessage(getBrand(), buf);
+
+    } else if (type == "sync.quota_full") {
+        /* format: <repo_name\trepo_id> */
+        QStringList slist = content.split("\t");
+        if (slist.count() != 2) {
+            qWarning("Bad sync.quota_full message format");
+            return;
+        }
+
+        QString buf = tr("\"%1\" failed to sync.\nThe library owner's storage space is used up.").arg(slist.at(0));
+        seafApplet->trayIcon()->showMessage(getBrand(), buf);
+    }
+}
diff --git a/src/message-poller.h b/src/message-poller.h
new file mode 100644 (file)
index 0000000..f7aff7a
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef SEAFILE_CLIENT_MESSAGE_POLLER_H
+#define SEAFILE_CLIENT_MESSAGE_POLLER_H
+
+#include <QObject>
+
+class QTimer;
+class SeafileRpcClient;
+
+struct SyncNotification;
+
+class MessagePoller : public QObject {
+    Q_OBJECT
+public:
+    MessagePoller(QObject *parent=0);
+    ~MessagePoller();
+
+    void start();
+
+private slots:
+    void onDaemonDead();
+    void onDaemonRestarted();
+    void checkNotification();
+
+private:
+    Q_DISABLE_COPY(MessagePoller)
+
+    void processNotification(const SyncNotification& notification);
+
+    SeafileRpcClient *rpc_client_;
+
+    QTimer *check_notification_timer_;
+};
+
+#endif // SEAFILE_CLIENT_MESSAGE_POLLER_H
diff --git a/src/network-mgr.cpp b/src/network-mgr.cpp
new file mode 100644 (file)
index 0000000..f69abbb
--- /dev/null
@@ -0,0 +1,252 @@
+#include <QNetworkAccessManager>
+#include <QNetworkProxy>
+#include <algorithm>
+#include <QStringRef>
+#include <QSslConfiguration>
+#include <QSslSocket>
+#include <QSslCipher>
+#include <QTimer>
+#include <QMutexLocker>
+
+#include "utils/utils-mac.h"
+#include "api/api-client.h"
+#include "filebrowser/tasks.h"
+#include "server-status-service.h"
+
+#include "network-mgr.h"
+
+namespace {
+
+const int kCheckNetworkStatusIntervalMSecs = 10 * 1000; // 10s
+
+QNetworkProxy proxy_;
+
+template <class T, std::size_t N>
+inline size_t ArrayLengthOf(T (&)[N]) {
+  return N;
+}
+
+const char *const kWhitelistCiphers[] = {
+    "ECDHE-RSA-AES256-GCM-SHA384"
+    "ECDHE-RSA-AES128-GCM-SHA256"
+    "DHE-RSA-AES256-GCM-SHA384"
+    "DHE-RSA-AES128-GCM-SHA256"
+    "ECDHE-RSA-AES256-SHA384"
+    "ECDHE-RSA-AES128-SHA256"
+    "ECDHE-RSA-AES256-SHA"
+    "ECDHE-RSA-AES128-SHA"
+    "DHE-RSA-AES256-SHA256"
+    "DHE-RSA-AES128-SHA256"
+    "DHE-RSA-AES256-SHA"
+    "DHE-RSA-AES128-SHA"
+    "ECDHE-RSA-DES-CBC3-SHA"
+    "EDH-RSA-DES-CBC3-SHA"
+    "AES256-GCM-SHA384"
+    "AES128-GCM-SHA256"
+    "AES256-SHA256"
+    "AES128-SHA256"
+    "AES256-SHA"
+    "AES128-SHA"
+    "DES-CBC3-SHA"
+};
+
+// return false if it contains RC4, RSK, CBC, MD5, DES, DSS, EXPORT, NULL
+bool isWeakCipher(const QString& cipher_name)
+{
+    int current_begin = 0;
+    int current_end;
+    QStringRef name;
+    while((current_end = cipher_name.indexOf("-", current_begin)) != -1) {
+        name = QStringRef(&cipher_name, current_begin, current_end - current_begin);
+        if (name == "RC4")
+            return true;
+        else if (name == "PSK")
+            return true;
+        else if (name == "CBC")
+            return true;
+        else if (name == "MD5")
+            return true;
+        else if (name == "DES")
+            return true;
+        else if (name == "DSS")
+            return true;
+        else if (name == "EXP")
+            return true;
+        else if (name == "NULL")
+            return true;
+
+        current_begin = current_end + 1;
+    }
+    return false;
+}
+
+void disableWeakCiphers()
+{
+    QSslConfiguration configuration = QSslConfiguration::defaultConfiguration();
+    const QList<QSslCipher> ciphers = QSslSocket::supportedCiphers();
+
+    QList<QSslCipher> new_ciphers;
+    Q_FOREACH(const QSslCipher &cipher, ciphers)
+    {
+        bool whitelisted = false;
+        for (unsigned i = 0; i < ArrayLengthOf(kWhitelistCiphers); ++i) {
+            if (cipher.name() == kWhitelistCiphers[i]) {
+                whitelisted = true;
+                break;
+            }
+        }
+        if (!whitelisted) {
+            // blacklist eNULL, no encryption
+            if (cipher.encryptionMethod().isEmpty())
+                continue;
+            // blacklist aNULL, no authentication
+            if (cipher.authenticationMethod().isEmpty())
+                continue;
+            // blacklist RC4, RSK, CBC, MD5, DES, DSS, EXPORT, NULL
+            const QString cipher_name = cipher.name();
+            if (isWeakCipher(cipher_name))
+                continue;
+        }
+        new_ciphers.push_back(cipher);
+    }
+    configuration.setCiphers(new_ciphers);
+    QSslConfiguration::setDefaultConfiguration(configuration);
+}
+
+#ifdef Q_OS_MAC
+void loadUserCaCertificate()
+{
+    QList<QSslCertificate> certificates;
+    const std::vector<QByteArray> certs = utils::mac::getSystemCaCertificates();
+    for (unsigned i = 0; i < certs.size(); ++i)
+    {
+        certificates.append(QSslCertificate::fromData(certs[i], QSsl::Der));
+    }
+
+    // remove duplicates
+    certificates = certificates.toSet().toList();
+
+    QSslSocket::setDefaultCaCertificates(certificates);
+}
+#endif
+} // anonymous namespace
+
+NetworkManager* NetworkManager::instance_ = NULL;
+
+NetworkManager::NetworkManager() : should_retry_(true) {
+    // remove unsafe cipher
+    disableWeakCiphers();
+
+#ifdef Q_OS_MAC
+    // load user ca certificate from system, mac only
+    loadUserCaCertificate();
+#endif
+}
+
+void NetworkManager::addWatch(QNetworkAccessManager* manager)
+{
+    if (std::find(managers_.begin(), managers_.end(), manager) == managers_.end()) {
+        connect(manager, SIGNAL(destroyed()), this, SLOT(onCleanup()));
+        managers_.push_back(manager);
+    }
+}
+
+void NetworkManager::applyProxy(const QNetworkProxy& proxy)
+{
+    proxy_ = proxy;
+    should_retry_ = true;
+    QNetworkProxy::setApplicationProxy(proxy_);
+    for(std::vector<QNetworkAccessManager*>::iterator pos = managers_.begin();
+        pos != managers_.end(); ++pos)
+        (*pos)->setProxy(proxy_);
+    emit proxyChanged(proxy_);
+}
+
+void NetworkManager::reapplyProxy()
+{
+    applyProxy(proxy_);
+}
+
+void NetworkManager::onCleanup()
+{
+    // Don't use "qobject_cast<QNetworkAccessManager>" here, because the
+    // "destroyed" signal is emited by QObject class, so qobject_cast would fail
+    // to cast it to QNetworkAccessManager.
+    QNetworkAccessManager *manager = (QNetworkAccessManager*)(sender());
+    managers_.erase(std::remove(managers_.begin(), managers_.end(), manager),
+                    managers_.end());
+}
+
+SINGLETON_IMPL(NetworkStatusDetector)
+
+NetworkStatusDetector::NetworkStatusDetector() {
+    has_network_failure_ = false;
+
+    check_timer_ = new QTimer(this);
+    connect(check_timer_, &QTimer::timeout, this, &NetworkStatusDetector::detect);
+}
+
+NetworkStatusDetector::~NetworkStatusDetector() {
+}
+
+void NetworkStatusDetector::start() {
+    qWarning("Starting the network status detector");
+    check_timer_->start(kCheckNetworkStatusIntervalMSecs);
+}
+
+void NetworkStatusDetector::stop() {
+    check_timer_->stop();
+}
+
+void NetworkStatusDetector::detect() {
+    bool need_reset = false;
+
+    {
+        QMutexLocker lock(&network_error_mutex_);
+        if (has_network_failure_) {
+            has_network_failure_ = false;
+            need_reset = true;
+        }
+    }
+
+    if (need_reset) {
+        qWarning("[network detector] resetting the qt network access manager");
+        SeafileApiClient::resetQNAM();
+        FileServerTask::resetQNAM();
+        ServerStatusService::instance()->refreshUnconnected();
+    }
+}
+
+// Whether the given error may indicate a network reset, e.g. when the
+// computer wakes up after sleeping/hibernating
+bool NetworkStatusDetector::shouldTreatErrorAsNetworkReset(QNetworkReply::NetworkError error)
+{
+    switch (error) {
+    case QNetworkReply::ConnectionRefusedError:
+    case QNetworkReply::SslHandshakeFailedError:
+    case QNetworkReply::RemoteHostClosedError:
+        return false;
+    default:
+        return true;
+    }
+}
+
+void NetworkStatusDetector::setNetworkFailure(QNetworkReply::NetworkError error) {
+    if (!shouldTreatErrorAsNetworkReset(error)) {
+        return;
+    }
+
+    QMutexLocker lock(&network_error_mutex_);
+    if (!has_network_failure_) {
+        qWarning("[network detector] got a network failure: %d", (int)error);
+        has_network_failure_ = true;
+    }
+}
+
+void NetworkStatusDetector::setNetworkSuccess() {
+    // TODO: what if the successful requests are for a local server?
+    // if (has_network_failure_) {
+    //     qDebug("[network detector] got a network success");
+    //     has_network_failure_ = false;
+    // }
+}
diff --git a/src/network-mgr.h b/src/network-mgr.h
new file mode 100644 (file)
index 0000000..5576bea
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef SEAFILE_CLIENT_NETWORK_MANAGER_H
+#define SEAFILE_CLIENT_NETWORK_MANAGER_H
+
+#include <QObject>
+#include <vector>
+#include <QNetworkReply>
+#include <QMutex>
+
+#include "utils/singleton.h"
+
+class QNetworkAccessManager;
+class QNetworkProxy;
+class QTimer;
+
+class NetworkManager : public QObject {
+  Q_OBJECT
+public:
+    static NetworkManager* instance() {
+        if (!instance_) {
+            static NetworkManager singleton;
+            instance_ = &singleton;
+        }
+        return instance_;
+    }
+    void addWatch(QNetworkAccessManager* manager);
+    void applyProxy(const QNetworkProxy& proxy);
+    void reapplyProxy();
+
+    // retry only once
+    bool shouldRetry(const QNetworkReply::NetworkError error) {
+        if ((error == QNetworkReply::ProxyConnectionClosedError ||
+             error == QNetworkReply::ProxyConnectionRefusedError ||
+             error == QNetworkReply::ProxyNotFoundError ||
+             error == QNetworkReply::ProxyTimeoutError ||
+             error == QNetworkReply::UnknownProxyError) &&
+            should_retry_) {
+            NetworkManager::instance()->reapplyProxy();
+            should_retry_ = false;
+            return true;
+        }
+        return false;
+    }
+
+signals:
+    void proxyChanged(const QNetworkProxy& proxy);
+
+private slots:
+    void onCleanup();
+
+private:
+    std::vector<QNetworkAccessManager*> managers_;
+    NetworkManager();
+    ~NetworkManager() {}
+    NetworkManager(const NetworkManager&) /* = delete */ ;
+    bool should_retry_;
+    static NetworkManager* instance_;
+};
+
+// Check the network connection periodically, and reset the qt
+// QNetworkAccessManager if the network is reconnected.
+class NetworkStatusDetector: public QObject
+{
+    Q_OBJECT
+    SINGLETON_DEFINE(NetworkStatusDetector)
+public:
+    ~NetworkStatusDetector();
+    void start();
+    void stop();
+    void setNetworkFailure(QNetworkReply::NetworkError err);
+    void setNetworkSuccess();
+
+public slots:
+    void detect();
+
+signals:
+    void check();
+
+private:
+    NetworkStatusDetector();
+    bool shouldTreatErrorAsNetworkReset(QNetworkReply::NetworkError error);
+    QMutex network_error_mutex_;
+
+    QTimer *check_timer_;
+    bool has_network_failure_;
+};
+
+
+#endif // SEAFILE_CLIENT_NETWORK_MANAGER_H
diff --git a/src/open-local-helper.cpp b/src/open-local-helper.cpp
new file mode 100644 (file)
index 0000000..0755161
--- /dev/null
@@ -0,0 +1,145 @@
+#if defined(Q_OS_WIN32)
+#include <shellapi.h>
+#endif
+
+#include <QDesktopServices>
+#include <QUrl>
+#include <QUrlQuery>
+#include <QVariant>
+
+extern "C" {
+#include <searpc-client.h>
+
+#include <searpc.h>
+#include <seafile/seafile.h>
+#include <seafile/seafile-object.h>
+
+}
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "ui/main-window.h"
+#include "rpc/rpc-client.h"
+#include "rpc/rpc-server.h"
+#include "rpc/local-repo.h"
+
+#include "account.h"
+#include "repo-service.h"
+#include "open-local-helper.h"
+
+namespace {
+
+const char *kSeafileProtocolScheme = "seafile";
+const char *kSeafileProtocolHostOpenFile = "openfile";
+
+
+} // namespace
+
+OpenLocalHelper* OpenLocalHelper::singleton_ = NULL;
+
+OpenLocalHelper::OpenLocalHelper()
+{
+    url_ = NULL;
+
+    QDesktopServices::setUrlHandler(kSeafileProtocolScheme, this, SLOT(openLocalFile(const QUrl&)));
+}
+
+OpenLocalHelper*
+OpenLocalHelper::instance()
+{
+    if (singleton_ == NULL) {
+        static OpenLocalHelper instance;
+        singleton_ = &instance;
+    }
+
+    return singleton_;
+}
+
+QUrl OpenLocalHelper::generateLocalFileSeafileUrl(const QString& repo_id, const Account& account, const QString& path)
+{
+    QUrl url;
+    url.setScheme(kSeafileProtocolScheme);
+    url.setHost(kSeafileProtocolHostOpenFile);
+
+    QUrlQuery url_query;
+    url_query.addQueryItem("repo_id",  repo_id);
+    url_query.addQueryItem("path",  path);
+    url.setQuery(url_query);
+
+    return url;
+}
+
+QUrl OpenLocalHelper::generateLocalFileWebUrl(const QString& repo_id, const Account& account, const QString& path)
+{
+    QString fixed_path = path.startsWith("/") ? path : "/" + path;
+    if (fixed_path.endsWith("/"))
+        return account.getAbsoluteUrl("/#common/lib/" + repo_id + (fixed_path == "/" ?
+                                      "/" : fixed_path.left(fixed_path.size() - 1)));
+    else
+        return account.getAbsoluteUrl("/lib/" + repo_id + "/file" + fixed_path);
+}
+
+bool OpenLocalHelper::openLocalFile(const QUrl &url)
+{
+    if (url.scheme() != kSeafileProtocolScheme) {
+        qWarning("[OpenLocalHelper] unknown scheme %s\n", url.scheme().toUtf8().data());
+        return false;
+    }
+
+    if (url.host() != kSeafileProtocolHostOpenFile) {
+        qWarning("[OpenLocalHelper] unknown command %s\n", url.host().toUtf8().data());
+        return false;
+    }
+
+    QUrlQuery url_query = QUrlQuery(url.query());
+    QString repo_id = url_query.queryItemValue("repo_id", QUrl::FullyDecoded);
+    QString email = url_query.queryItemValue("email", QUrl::FullyDecoded);
+    QString path = url_query.queryItemValue("path", QUrl::FullyDecoded);
+
+    if (repo_id.size() < 36) {
+        qWarning("[OpenLocalHelper] invalid repo_id %s\n", repo_id.toUtf8().data());
+        return false;
+    }
+
+    qDebug("[OpenLocalHelper] open local file: repo %s, path %s\n",
+           repo_id.toUtf8().data(), path.toUtf8().data());
+
+    RepoService::instance()->openLocalFile(repo_id, path);
+
+    return true;
+}
+
+void OpenLocalHelper::messageBox(const QString& msg)
+{
+    seafApplet->mainWindow()->showWindow();
+    seafApplet->messageBox(msg);
+}
+
+void OpenLocalHelper::handleOpenLocalFromCommandLine(const char *url)
+{
+    SeafileAppletRpcServer::Client *client = SeafileAppletRpcServer::getClient();
+    if (client->connect()) {
+        // An instance of seafile applet is running
+        client->sendOpenSeafileUrlCommand(QUrl::fromEncoded(url));
+        exit(0);
+    } else {
+        // No instance of seafile client running, we just record the url and
+        // let the applet start. The local file will be opened when the applet
+        // is ready.
+        setUrl(url);
+    }
+}
+
+void OpenLocalHelper::checkPendingOpenLocalRequest()
+{
+    if (!url_.isEmpty()) {
+        openLocalFile(QUrl::fromEncoded(url_));
+        setUrl(NULL);
+    }
+}
+
+bool OpenLocalHelper::activateRunningInstance()
+{
+    SeafileAppletRpcServer::Client *client = SeafileAppletRpcServer::getClient();
+    return client->connect() && client->sendActivateCommand();
+}
diff --git a/src/open-local-helper.h b/src/open-local-helper.h
new file mode 100644 (file)
index 0000000..264d3c8
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef SEAFILE_CLIENT_OPEN_LOCAL_FILE_HELPER_H
+#define SEAFILE_CLIENT_OPEN_LOCAL_FILE_HELPER_H
+
+#include <QObject>
+#include <QUrl>
+#include <QString>
+class Account;
+
+/**
+ * Helper class to handle open local file request
+ */
+class OpenLocalHelper : public QObject
+{
+    Q_OBJECT
+public:
+    static OpenLocalHelper* instance();
+
+    QUrl generateLocalFileSeafileUrl(const QString& repo_id, const Account& account, const QString& path);
+    QUrl generateLocalFileWebUrl(const QString& repo_id, const Account& account, const QString& path);
+
+    bool openLocalFile(const QUrl &url);
+
+    void setUrl(const char *url) { url_ = url; }
+
+    void handleOpenLocalFromCommandLine(const char *url);
+
+    void checkPendingOpenLocalRequest();
+
+    bool activateRunningInstance();
+
+private:
+    static OpenLocalHelper* singleton_;
+
+    OpenLocalHelper();
+
+    void messageBox(const QString& msg);
+
+    QByteArray url_;
+};
+
+
+#endif // SEAFILE_CLIENT_OPEN_LOCAL_FILE_HELPER_H
diff --git a/src/repo-service-helper.cpp b/src/repo-service-helper.cpp
new file mode 100644 (file)
index 0000000..c80ae39
--- /dev/null
@@ -0,0 +1,135 @@
+#include <QScopedPointer>
+#include <QDir>
+
+#include "repo-service-helper.h"
+
+#include "filebrowser/data-mgr.h"
+#include "filebrowser/progress-dialog.h"
+#include "filebrowser/file-browser-requests.h"
+#include "filebrowser/tasks.h"
+#include "filebrowser/auto-update-mgr.h"
+#include "filebrowser/transfer-mgr.h"
+
+#include "ui/set-repo-password-dialog.h"
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "repo-service.h"
+
+void FileDownloadHelper::openFile(const QString& path, bool work_around_mac_auto_udpate)
+{
+    QFileInfo file(path);
+    QString file_name = file.fileName();
+    if (!file.exists()) {
+        QString msg = QObject::tr("File \"%1\" doesn't exist in \"%2\"").arg(file_name).arg(file.path());
+        seafApplet->warningBox(msg);
+        return;
+    }
+    if (!::openInNativeExtension(path) && !::showInGraphicalShell(path)) {
+        QString msg = QObject::tr("%1 couldn't find an application to open file %2").arg(getBrand()).arg(file_name);
+        seafApplet->warningBox(msg);
+        return;
+    }
+#ifdef Q_OS_MAC
+    MacImageFilesWorkAround::instance()->fileOpened(path);
+#endif
+}
+
+FileDownloadHelper::FileDownloadHelper(const Account &account, const ServerRepo &repo, const QString &path, QWidget *parent)
+  : account_(account), repo_(repo), path_(path), file_name_(QFileInfo(path).fileName()), parent_(parent), req_(NULL) {
+}
+
+FileDownloadHelper::~FileDownloadHelper()
+{
+    onCancel();
+    if (req_)
+        req_->deleteLater();
+}
+
+void FileDownloadHelper::start()
+{
+    if (req_)
+        return;
+    const QString file_name = QFileInfo(path_).fileName();
+    const QString dirent_path = ::getParentPath(path_);
+    req_ = new GetDirentsRequest(account_, repo_.id, dirent_path);
+    connect(req_, SIGNAL(success(bool, const QList<SeafDirent> &, const QString&)),
+            this, SLOT(onGetDirentsSuccess(bool, const QList<SeafDirent> &)));
+    connect(req_, SIGNAL(failed(const ApiError &)),
+            this, SLOT(onGetDirentsFailure(const ApiError &)));
+    req_->send();
+}
+
+void FileDownloadHelper::onCancel()
+{
+    if (req_)
+        disconnect(req_, 0, this, 0);
+}
+
+void FileDownloadHelper::onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent> &dirents)
+{
+    Q_UNUSED(current_readonly);
+    bool found_file = false;
+    Q_FOREACH(const SeafDirent &dirent, dirents)
+    {
+        if (dirent.name == file_name_) {
+            if (dirent.isDir()) {
+                RepoService::instance()->openFolder(repo_.id, path_);
+                return;
+            }
+            downloadFile(dirent.id);
+            found_file = true;
+            break;
+        }
+    }
+    // critally important
+    if (!found_file) {
+        QString msg = QObject::tr("File \"%1\" doesn't exist in \"%2\"").arg(file_name_).arg(QFileInfo(path_).path());
+        seafApplet->warningBox(msg);
+    }
+
+}
+
+void FileDownloadHelper::downloadFile(const QString &id)
+{
+    DataManager *data_mgr = seafApplet->dataManager();
+    QString cached_file = data_mgr->getLocalCachedFile(repo_.id, path_, id);
+    if (!cached_file.isEmpty()) {
+        openFile(cached_file, false);
+        return;
+    }
+
+    // endless loop for setPasswordDialog
+    while(true) {
+        if (TransferManager::instance()->getDownloadTask(repo_.id, path_) != nullptr) {
+            return;
+        }
+        QScopedPointer<FileDownloadTask> task(data_mgr->createDownloadTask(repo_.id, path_));
+        task->setAutoDelete(false);
+        FileBrowserProgressDialog dialog(task.data(), parent_);
+        if (dialog.exec()) {
+            QString full_path =
+                data_mgr->getLocalCachedFile(repo_.id, path_, task->fileId());
+            if (!full_path.isEmpty())
+                openFile(full_path, true);
+            break;
+        }
+        // if the user canceled the task, don't bother it
+        if (task->error() == FileNetworkTask::TaskCanceled)
+            break;
+        // if the repo_sitory is encrypted and password is incorrect
+        if (repo_.encrypted && task->httpErrorCode() == 400) {
+            SetRepoPasswordDialog password_dialog(repo_, parent_);
+            if (password_dialog.exec())
+                continue;
+            // the user canceled the dialog? skip
+            break;
+        }
+        // printf ("error = %d\n", (int)task->error());
+        QString msg =
+            QObject::tr("Unable to download item \"%1\"").arg(path_);
+        seafApplet->warningBox(msg);
+        break;
+    }
+}
diff --git a/src/repo-service-helper.h b/src/repo-service-helper.h
new file mode 100644 (file)
index 0000000..2995563
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef SEAFILE_CLIENT_REPO_SERVICE_HELPER_H_
+#define SEAFILE_CLIENT_REPO_SERVICE_HELPER_H_
+
+#include <QObject>
+#include <QString>
+#include <QList>
+#include <QScopedPointer>
+
+#include "account.h"
+#include "api/api-error.h"
+#include "api/server-repo.h"
+#include "filebrowser/seaf-dirent.h"
+#include "filebrowser/data-mgr.h"
+
+class GetDirentsRequest;
+class QWidget;
+
+class FileDownloadHelper : public QObject {
+    Q_OBJECT
+public:
+    static void openFile(const QString& path, bool work_around_mac_auto_udpate);
+    FileDownloadHelper(const Account &account, const ServerRepo &repo, const QString &path, QWidget *parent);
+    ~FileDownloadHelper();
+    void start();
+
+private slots:
+
+    void onCancel();
+    void onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent> &dirents);
+    void onGetDirentsFailure(const ApiError &)
+    {
+        downloadFile(QString());
+    }
+
+private:
+    void downloadFile(const QString &id);
+
+    const Account account_;
+    const ServerRepo repo_;
+    const QString path_;
+    const QString file_name_;
+    QWidget *parent_;
+    GetDirentsRequest *req_;
+};
+
+#endif // SEAFILE_CLIENT_REPO_SERVICE_HELPER_H_
diff --git a/src/repo-service.cpp b/src/repo-service.cpp
new file mode 100644 (file)
index 0000000..6986d70
--- /dev/null
@@ -0,0 +1,629 @@
+#include <unistd.h>
+#include <algorithm>
+
+#include <sqlite3.h>
+
+#include <QTimer>
+#include <QDir>
+#include <QSet>
+#include <QDesktopServices>
+#include <QThreadPool>
+
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "rpc/clone-task.h"
+#include "account-mgr.h"
+#include "api/server-repo.h"
+#include "api/requests.h"
+#include "ui/main-window.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/uninstall-helpers.h"
+
+#include "filebrowser/file-browser-manager.h"
+#include "filebrowser/data-cache.h"
+#include "filebrowser/data-mgr.h"
+
+#include "repo-service.h"
+#include "repo-service-helper.h"
+#include "open-local-helper.h"
+
+namespace {
+
+class SyncedSubfolder {
+public:
+    SyncedSubfolder() {}
+    SyncedSubfolder(const QString &repo_id, const QString &parent_repo_id,
+                    const QString &parent_path)
+        : repo_id_(repo_id), parent_repo_id_(parent_repo_id),
+          parent_path_(parent_path) {}
+    SyncedSubfolder(const ServerRepo &repo, const ServerRepo &parent_repo,
+                    const QString &parent_path)
+        : repo_id_(repo.id), parent_repo_id_(parent_repo.id),
+          parent_path_(parent_path) {}
+    SyncedSubfolder(const SyncedSubfolder &rhs)
+        : repo_id_(rhs.repo_id_), parent_repo_id_(rhs.parent_repo_id_),
+          parent_path_(rhs.parent_path_) {}
+
+    SyncedSubfolder& operator=(const SyncedSubfolder &rhs)
+    {
+        repo_id_ = rhs.repo_id_;
+        parent_repo_id_ = rhs.parent_repo_id_;
+        parent_path_ = rhs.parent_path_;
+        return *this;
+    }
+
+    const QString& repoId() const { return repo_id_; }
+    const QString& parentRepoId() const { return parent_repo_id_; }
+    const QString& parentPath() const { return parent_path_; }
+
+    bool isValid() const { return !repo_id_.isEmpty(); }
+
+private:
+    QString repo_id_;
+    QString parent_repo_id_;
+    QString parent_path_;
+};
+
+const int kRefreshReposInterval = 1000 * 60 * 5; // 5 min
+
+bool loadSyncedFolderCB(sqlite3_stmt *stmt, void *data)
+{
+    std::vector<SyncedSubfolder> *synced_subfolders = static_cast<std::vector<SyncedSubfolder> *>(data);
+    const char *repo_id = (const char *)sqlite3_column_text (stmt, 0);
+    const char *parent_repo_id = (const char *)sqlite3_column_text (stmt, 1);
+    const char *parent_path = (const char *)sqlite3_column_text (stmt, 2);
+    synced_subfolders->push_back(SyncedSubfolder(repo_id, parent_repo_id, parent_path));
+
+    return true;
+}
+
+// TODO: use lambda to replace this helper class if we are switching to C++11
+template<class T>
+class RepohasRepoID {
+public:
+    RepohasRepoID(const QString &repo_id) : repo_id_(repo_id) {}
+    bool operator()(const T &repo) {
+        return repo.id == repo_id_;
+    }
+
+private:
+    const QString& repo_id_;
+};
+
+class SyncedSubfolderhasRepoID {
+public:
+    SyncedSubfolderhasRepoID(const QString &repo_id) : repo_id_(repo_id) {}
+    bool operator()(const SyncedSubfolder &subfolder) {
+        return subfolder.repoId() == repo_id_;
+    }
+
+private:
+    const QString& repo_id_;
+};
+
+// don't rely on this,
+// it is used for get repo request only
+std::vector<SyncedSubfolder> synced_subfolders_;
+
+} // namespace
+
+SINGLETON_IMPL(RepoService)
+
+RepoService::RepoService(QObject *parent)
+    : QObject(parent), synced_subfolder_db_(NULL)
+{
+    refresh_timer_ = new QTimer(this);
+    connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refresh()));
+    list_repo_req_ = NULL;
+    in_refresh_ = false;
+    wipe_in_progress_ = false;
+}
+
+RepoService::~RepoService()
+{
+    if (synced_subfolder_db_)
+        sqlite3_close(synced_subfolder_db_);
+}
+
+void RepoService::start()
+{
+    const char *errmsg;
+
+    if (!synced_subfolder_db_) {
+        do {
+            QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("accounts.db");
+            if (sqlite3_open (db_path.toUtf8().data(), &synced_subfolder_db_)) {
+                errmsg = sqlite3_errmsg (synced_subfolder_db_);
+                qWarning("failed to open synced subfolder database %s: %s",
+                        db_path.toUtf8().data(), errmsg ? errmsg : "no error given");
+
+                sqlite3_close(synced_subfolder_db_);
+                synced_subfolder_db_ = NULL;
+                break;
+            }
+
+            // enabling foreign keys, it must be done manually from each connection
+            // and this feature is only supported from sqlite 3.6.19
+            const char *sql = "PRAGMA foreign_keys=ON;";
+            if (sqlite_query_exec (synced_subfolder_db_, sql) < 0) {
+                qWarning("sqlite version is too low to support foreign key feature\n");
+                qWarning("feature synced_sub_folder is disabled\n");
+                sqlite3_close(synced_subfolder_db_);
+                synced_subfolder_db_ = NULL;
+                break;
+            }
+
+            // create SyncedSubfolder table
+            sql = "CREATE TABLE IF NOT EXISTS SyncedSubfolder ("
+                "repo_id TEXT PRIMARY KEY, parent_repo_id TEXT NOT NULL, "
+                "url VARCHAR(24), username VARCHAR(15), "
+                "parent_path TEXT NOT NULL, "
+                "FOREIGN KEY(url, username) REFERENCES Accounts(url, username) "
+                "ON DELETE CASCADE ON UPDATE CASCADE )";
+            if (sqlite_query_exec (synced_subfolder_db_, sql) < 0) {
+                qWarning("failed to create synced subfolder table\n");
+                sqlite3_close(synced_subfolder_db_);
+                synced_subfolder_db_ = NULL;
+            }
+        } while (0);
+    }
+
+    refresh_timer_->start(kRefreshReposInterval);
+}
+
+void RepoService::stop()
+{
+    refresh_timer_->stop();
+}
+
+void RepoService::refreshLocalRepoList() {
+    // local_repos_.clear(); is called intenally
+    if (seafApplet->rpcClient()->listLocalRepos(&local_repos_) < 0) {
+        qWarning("unable to refresh local repos\n");
+    }
+}
+
+void RepoService::refresh()
+{
+    if (in_refresh_) {
+        return;
+    }
+
+    const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+    if (accounts.empty()) {
+        in_refresh_ = false;
+        return;
+    }
+
+    const Account *account = &accounts.front();
+
+    if (!account->isValid())
+        return;
+
+    in_refresh_ = true;
+
+    if (!get_repo_reqs_.empty()) {
+        for (std::list<GetRepoRequest*>::iterator pos = get_repo_reqs_.begin(); pos != get_repo_reqs_.end(); ++pos)
+          delete (*pos);
+        get_repo_reqs_.clear();
+    }
+
+    refreshLocalRepoList();
+
+    synced_subfolders_.clear();
+    if (synced_subfolder_db_) {
+
+        char *zql = sqlite3_mprintf("SELECT repo_id, parent_repo_id, parent_path FROM SyncedSubfolder "
+                                    "WHERE url = %Q AND username = %Q",
+                                    account->serverUrl.toEncoded().data(),
+                                    account->username.toUtf8().data());;
+        sqlite_foreach_selected_row (synced_subfolder_db_, zql,
+                                     loadSyncedFolderCB, &synced_subfolders_);
+        sqlite3_free(zql);
+
+        std::vector<CloneTask> tasks;
+        seafApplet->rpcClient()->getCloneTasks(&tasks);
+
+        QSet<QString> local_repos;
+        for (size_t i = 0; i < tasks.size(); ++i) {
+            local_repos.insert(tasks[i].repo_id);
+        }
+        for (size_t i = 0; i < local_repos_.size(); ++i) {
+            local_repos.insert(local_repos_[i].id);
+        }
+
+        // If the synced virtual repo no longer exists locally, remove it from
+        // applet database.
+        for (size_t i = 0; i < synced_subfolders_.size(); ++i) {
+            if (!local_repos.contains(synced_subfolders_[i].repoId())) {
+              removeSyncedSubfolder(synced_subfolders_[i].repoId());
+            }
+        }
+    }
+
+    if (list_repo_req_) {
+        list_repo_req_->deleteLater();
+    }
+
+    list_repo_req_ = new ListReposRequest(*account);
+
+    connect(list_repo_req_, SIGNAL(success(const std::vector<ServerRepo>&)),
+            this, SLOT(onRefreshSuccess(const std::vector<ServerRepo>&)));
+
+    connect(list_repo_req_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onRefreshFailed(const ApiError&)));
+    list_repo_req_->send();
+}
+
+void RepoService::onRefreshSuccess(const std::vector<ServerRepo>& repos)
+{
+    in_refresh_ = false;
+
+    server_repos_ = repos;
+
+    OpenLocalHelper::instance()->checkPendingOpenLocalRequest();
+
+    // if we have local repo missed in server_repos
+    // start a GetRepoRequest for it
+    for (size_t i = 0; i < synced_subfolders_.size(); ++i) {
+        bool found = false;
+        for (size_t j = 0; j < server_repos_.size(); ++j) {
+            if (synced_subfolders_[i].repoId() == server_repos_[j].id) {
+                found = true;
+                server_repos_[j].parent_repo_id = synced_subfolders_[i].parentRepoId();
+                server_repos_[j].parent_path = synced_subfolders_[i].parentPath();
+                break;
+            }
+        }
+        // create GetRepoRequest
+        if (!found)
+            startGetRequestFor(synced_subfolders_[i].repoId());
+    }
+
+    if (get_repo_reqs_.empty())
+        emit refreshSuccess(repos);
+}
+
+void RepoService::onRefreshFailed(const ApiError& error)
+{
+    in_refresh_ = false;
+
+    if (list_repo_req_->reply()->hasRawHeader("X-Seafile-Wiped")) {
+        qWarning ("current device is marked to be remote wiped\n");
+        // TODO: Remote wipe should be managed in a separate module, not here.
+        if (!wipe_in_progress_) {
+            wipe_in_progress_ = true;
+            wipeLocalFiles();
+        }
+        return;
+    }
+
+    // for the new version of seafile server
+    // we may have a 401 response whenever invalid token is used.
+    // see more: https://github.com/haiwen/seahub/commit/94dcfe338a52304f5895914ac59540b6176c679e
+    // but we only handle this error here to avoid complicate code since it is
+    // general enough.
+    // TODO move this handling to all possible cases
+    if (error.type() == ApiError::HTTP_ERROR && error.httpErrorCode() == 401) {
+        seafApplet->accountManager()->invalidateCurrentLogin();
+        return;
+    }
+
+    emit refreshFailed(error);
+}
+
+void RepoService::refresh(bool force)
+{
+    if (!force || !in_refresh_) {
+        refresh();
+        return;
+    }
+
+    // Abort the current request and send another
+    in_refresh_ = false;
+    refresh();
+}
+
+ServerRepo
+RepoService::getRepo(const QString& repo_id) const
+{
+    size_t n = server_repos_.size();
+    for (size_t i = 0; i < n; i++) {
+        const ServerRepo &repo = server_repos_[i];
+        if (repo.id == repo_id) {
+            return repo;
+        }
+    }
+
+    return ServerRepo();
+}
+
+void RepoService::openLocalFile(const QString& repo_id,
+                                const QString& path_in_repo,
+                                QWidget *dialog_parent)
+{
+    if (path_in_repo.endsWith("/")) {
+        openFolder(repo_id, path_in_repo.left(path_in_repo.size() - 1));
+        return;
+    }
+    qDebug("trying to open file %s in library %s", path_in_repo.toUtf8().data(), repo_id.toUtf8().data());
+
+    LocalRepo r;
+
+    seafApplet->rpcClient()->getLocalRepo(repo_id, &r);
+
+    if (r.isValid()) {
+        QString local_path = ::pathJoin(r.worktree, path_in_repo);
+
+        FileDownloadHelper::openFile(local_path, false);
+    } else {
+        ServerRepo repo = getRepo(repo_id);
+        if (!repo.isValid()) {
+            QString msg = tr("Unable to open file \"%1\" from nonexistent library \"%2\"").arg(path_in_repo).arg(repo_id);
+            seafApplet->warningBox(msg);
+            return;
+        }
+
+        const QString path = "/" + path_in_repo;
+        //TODO select the correct account
+        const Account account = seafApplet->accountManager()->currentAccount();
+        if (!account.isValid()) {
+            qWarning("no valid account found");
+            return;
+        }
+        FileDownloadHelper *helper =
+          new FileDownloadHelper(account, repo, path, dialog_parent);
+        helper->setParent(dialog_parent);
+        helper->start();
+    }
+}
+
+void RepoService::openFolder(const QString &repo_id,
+                             const QString &path_in_repo)
+{
+    qDebug("trying to open folder %s in library %s", path_in_repo.toUtf8().data(), repo_id.toUtf8().data());
+    LocalRepo r;
+
+    seafApplet->rpcClient()->getLocalRepo(repo_id, &r);
+
+    if (r.isValid()) {
+        QString local_path = ::pathJoin(r.worktree, path_in_repo);
+
+        FileDownloadHelper::openFile(local_path, false);
+    } else {
+        QString fixed_path = path_in_repo == "." ? "/" : path_in_repo;
+        ServerRepo repo = getRepo(repo_id);
+        if (!repo.isValid()) {
+            QString msg = tr("Unable to open file \"%1\" from nonexistent library \"%2\"").arg(path_in_repo).arg(repo_id);
+            seafApplet->warningBox(msg);
+            return;
+        }
+
+        //TODO select the correct account
+        const Account account = seafApplet->accountManager()->currentAccount();
+        if (!account.isValid()) {
+            qWarning("no valid account found");
+            return;
+        }
+        FileBrowserManager::getInstance()->openOrActivateDialog(account, repo, fixed_path);
+    }
+}
+
+void RepoService::onGetRequestSuccess(const ServerRepo& repo)
+{
+    GetRepoRequest* req = qobject_cast<GetRepoRequest*>(sender());
+    if (!req)
+        return;
+
+    SyncedSubfolderhasRepoID subfolder_helper(repo.id);
+    std::vector<SyncedSubfolder>::iterator pos = std::find_if(synced_subfolders_.begin(), synced_subfolders_.end(), subfolder_helper);
+
+    if (pos != synced_subfolders_.end()) {
+        ServerRepo fixed_repo = repo;
+        fixed_repo.parent_path = pos->parentPath();
+        fixed_repo.parent_repo_id = pos->parentRepoId();
+        server_repos_.push_back(fixed_repo);
+    }
+
+    // delete current request
+    req->deleteLater();
+    get_repo_reqs_.pop_front();
+
+    // start the next request or mark it as success
+    if (!get_repo_reqs_.empty())
+        get_repo_reqs_.front()->send();
+    else
+        emit refreshSuccess(server_repos_);
+}
+
+void RepoService::onGetRequestFailed(const ApiError& /*error*/)
+{
+    GetRepoRequest* req = qobject_cast<GetRepoRequest*>(sender());
+    if (!req)
+        return;
+
+    // delete current request
+    req->deleteLater();
+    get_repo_reqs_.pop_front();
+
+    // start the next request or mark it as success
+    if (!get_repo_reqs_.empty())
+        get_repo_reqs_.front()->send();
+    else
+        emit refreshSuccess(server_repos_);
+}
+
+void RepoService::startGetRequestFor(const QString &repo_id)
+{
+    bool was_empty = get_repo_reqs_.empty();
+    GetRepoRequest *req = new GetRepoRequest(seafApplet->accountManager()->currentAccount(), repo_id);
+    get_repo_reqs_.push_back(req);
+    connect(req, SIGNAL(success(const ServerRepo&)), this, SLOT(onGetRequestSuccess(const ServerRepo&)));
+    connect(req, SIGNAL(failed(const ApiError&)), this, SLOT(onGetRequestFailed(const ApiError&)));
+    if (was_empty)
+        req->send();
+}
+
+void RepoService::saveSyncedSubfolder(const ServerRepo& subfolder)
+{
+    const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+    if (accounts.empty() || !subfolder.isSubfolder())
+        return;
+    const Account *account = &accounts.front();
+
+    // if we have it before
+    RepohasRepoID<ServerRepo> repo_helper(subfolder.id);
+    std::vector<ServerRepo>::iterator pos = std::find_if(server_repos_.begin(), server_repos_.end(), repo_helper);
+    if (pos == server_repos_.end()) {
+        server_repos_.push_back(subfolder);
+    } else {
+        pos->parent_path = subfolder.parent_path;
+        pos->parent_repo_id = subfolder.parent_repo_id;
+    }
+
+    if (!synced_subfolder_db_) {
+        qWarning("synced subfolder database is not available\n");
+        return;
+    }
+
+    char *zql = sqlite3_mprintf(
+        "REPLACE INTO SyncedSubfolder(repo_id, parent_repo_id, url, username, "
+        "parent_path) VALUES (%Q, %Q, %Q, %Q, %Q)",
+        subfolder.id.toUtf8().data(), subfolder.parent_repo_id.toUtf8().data(),
+        account->serverUrl.toEncoded().data(),
+        account->username.toUtf8().data(),
+        subfolder.parent_path.toUtf8().data());
+    sqlite_query_exec (synced_subfolder_db_, zql);
+    sqlite3_free(zql);
+
+    emit refreshSuccess(server_repos_);
+}
+
+void RepoService::removeSyncedSubfolder(const QString& repo_id)
+{
+    char *zql = sqlite3_mprintf("DELETE FROM SyncedSubfolder WHERE repo_id = %Q", repo_id.toUtf8().data());
+    sqlite_query_exec(synced_subfolder_db_, zql);
+    sqlite3_free(zql);
+
+    SyncedSubfolderhasRepoID subfolder_helper(repo_id);
+    synced_subfolders_.erase(std::remove_if(synced_subfolders_.begin(), synced_subfolders_.end(), subfolder_helper), synced_subfolders_.end());
+
+    RepohasRepoID<ServerRepo> repo_helper(repo_id);
+    std::vector<ServerRepo>::iterator pos = std::remove_if(server_repos_.begin(), server_repos_.end(), repo_helper);
+    if (pos != server_repos_.end() && pos->isSubfolder()) {
+        server_repos_.erase(pos, server_repos_.end());
+
+        emit refreshSuccess(server_repos_);
+    }
+}
+
+void RepoService::removeCloudFileBrowserCache()
+{
+    QList<FileCache::CacheEntry> all_files =
+        FileCache::instance()->getAllCachedFiles();
+    const Account account = seafApplet->accountManager()->currentAccount();
+    foreach (const FileCache::CacheEntry& entry, all_files) {
+        if (account.getSignature() == entry.account_sig) {
+            QString fullpath = DataManager::getLocalCacheFilePath(entry.repo_id, entry.path);
+            printf ("removing cached file %s\n", toCStr(fullpath));
+            ::unlink((const char*)(toCStr(fullpath)));
+        }
+    }
+}
+
+
+void WipeFilesThread::run()
+{
+    for (size_t i = 0; i < local_repos_.size(); ++i) {
+        const LocalRepo& repo = local_repos_[i];
+        qWarning ("removing all files of repo %s: %s\n",
+                  toCStr(repo.name),
+                  toCStr(repo.worktree));
+        if (repo.worktree.length() > 1) {
+            delete_dir_recursively(repo.worktree);
+        }
+    }
+
+    for (int i = 0; i < cached_files_.size(); i++) {
+        ::unlink(toCStr(cached_files_[i]));
+    }
+
+    emit done();
+}
+
+void RepoService::wipeLocalFiles()
+{
+    const Account& account = seafApplet->accountManager()->currentAccount();
+
+    // Collect repo worktrees
+    std::vector<LocalRepo> repos_to_wipe;
+    seafApplet->rpcClient()->listLocalRepos(&local_repos_);
+    QStringList worktrees;
+    for (size_t i = 0; i < local_repos_.size(); ++i) {
+        const LocalRepo& repo = local_repos_[i];
+
+        QString repo_server_url;
+        if (seafApplet->rpcClient()->getRepoProperty(repo.id, "server-url", &repo_server_url) < 0) {
+            continue;
+        }
+        if (QUrl(repo_server_url).host() != account.serverUrl.host()) {
+            continue;
+        }
+
+        seafApplet->rpcClient()->unsync(repo.id);
+        repos_to_wipe.push_back(repo);
+    }
+
+    // Collect files cached by cloud file browser
+    QStringList cached_files;
+    QList<FileCache::CacheEntry> all_files =
+        FileCache::instance()->getAllCachedFiles();
+    foreach (const FileCache::CacheEntry& entry, all_files) {
+        if (account.getSignature() == entry.account_sig) {
+            QString fullpath = DataManager::getLocalCacheFilePath(entry.repo_id, entry.path);
+            cached_files << DataManager::getLocalCacheFilePath(entry.repo_id, entry.path);
+        }
+    }
+
+    WipeFilesThread *wiper = new WipeFilesThread(repos_to_wipe, cached_files);
+    connect(wiper, SIGNAL(done()), this, SLOT(onWiperDone()));
+
+    QThreadPool::globalInstance()->start(wiper);
+}
+
+void RepoService::onWiperDone()
+{
+    RemoteWipeReportRequest *req = new RemoteWipeReportRequest(
+        seafApplet->accountManager()->currentAccount());
+
+    connect(req,
+            SIGNAL(success()),
+            this,
+            SLOT(onRemoteWipeReportSuccess()));
+
+    connect(req,
+            SIGNAL(failed(const ApiError &)),
+            this,
+            SLOT(onRemoteWipeReportFailed(const ApiError &)));
+
+    req->send();
+}
+
+void RepoService::onRemoteWipeReportSuccess()
+{
+    wipe_in_progress_ = false;
+    RemoteWipeReportRequest* req = qobject_cast<RemoteWipeReportRequest*>(sender());
+    req->deleteLater();
+    seafApplet->accountManager()->invalidateCurrentLogin();
+}
+
+void RepoService::onRemoteWipeReportFailed(const ApiError& error)
+{
+    wipe_in_progress_ = false;
+    RemoteWipeReportRequest* req = qobject_cast<RemoteWipeReportRequest*>(sender());
+    req->deleteLater();
+    seafApplet->accountManager()->invalidateCurrentLogin();
+}
diff --git a/src/repo-service.h b/src/repo-service.h
new file mode 100644 (file)
index 0000000..1d7b773
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef SEAFILE_CLIENT_REPO_SERVICE_H_
+#define SEAFILE_CLIENT_REPO_SERVICE_H_
+
+#include <vector>
+#include <QObject>
+#include <QRunnable>
+
+#include "utils/singleton.h"
+#include "rpc/local-repo.h"
+#include "api/server-repo.h"
+
+class QTimer;
+
+class ApiError;
+class ListReposRequest;
+class GetRepoRequest;
+
+struct sqlite3;
+
+
+class RepoService : public QObject {
+    SINGLETON_DEFINE(RepoService)
+    Q_OBJECT
+public:
+    void start();
+    void stop();
+
+    const std::vector<ServerRepo>& serverRepos() const { return server_repos_; }
+
+    const std::vector<LocalRepo>& localRepos() const { return local_repos_; }
+
+    ServerRepo getRepo(const QString& repo_id) const;
+
+    void saveSyncedSubfolder(const ServerRepo& subfolder);
+    void removeSyncedSubfolder(const QString& repo_id);
+
+    void refreshLocalRepoList();
+
+    void refresh(bool force);
+
+    void openLocalFile(const QString& repo_id,
+                       const QString& path_in_repo,
+                       QWidget *dialog_parent=0);
+
+    void openRepoOnSeahub(const QString& repo_id);
+
+    void openFolder(const QString &repo_id,
+                    const QString &path_in_repo);
+
+public slots:
+    void refresh();
+
+private slots:
+    void onRefreshSuccess(const std::vector<ServerRepo>& repos);
+    void onRefreshFailed(const ApiError& error);
+
+    void onGetRequestSuccess(const ServerRepo& repo);
+    void onGetRequestFailed(const ApiError& error);
+
+    void onWiperDone();
+
+    void onRemoteWipeReportSuccess();
+    void onRemoteWipeReportFailed(const ApiError& error);
+
+signals:
+    void refreshSuccess(const std::vector<ServerRepo>& repos);
+    void refreshFailed(const ApiError& error);
+
+private:
+    Q_DISABLE_COPY(RepoService)
+    ~RepoService();
+
+    RepoService(QObject *parent=0);
+
+    void startGetRequestFor(const QString &repo_id);
+    void wipeLocalFiles();
+    void removeCloudFileBrowserCache();
+
+    ListReposRequest *list_repo_req_;
+    std::list<GetRepoRequest*> get_repo_reqs_;
+    struct sqlite3 *synced_subfolder_db_;
+
+    std::vector<ServerRepo> server_repos_;
+    std::vector<LocalRepo> local_repos_;
+
+    QTimer *refresh_timer_;
+    bool in_refresh_;
+
+    bool wipe_in_progress_;
+};
+
+
+class WipeFilesThread : public QObject, public QRunnable
+{
+    Q_OBJECT
+public:
+    WipeFilesThread(const std::vector<LocalRepo>& local_repos,
+                    const QStringList& cached_files)
+        : local_repos_(local_repos),
+          cached_files_(cached_files) {};
+
+    void run();
+
+signals:
+    void done();
+
+private:
+    const std::vector<LocalRepo> local_repos_;
+    const QStringList cached_files_;
+};
+
+#endif // SEAFILE_CLIENT_REPO_SERVICE_H_
diff --git a/src/rpc/clone-task.cpp b/src/rpc/clone-task.cpp
new file mode 100644 (file)
index 0000000..66786a3
--- /dev/null
@@ -0,0 +1,194 @@
+#include <QObject>
+#include <QStringList>
+#include <glib-object.h>
+
+#include "utils/utils.h"
+#include "clone-task.h"
+
+CloneTask CloneTask::fromGObject(GObject *obj)
+{
+    CloneTask task;
+
+    char *state = NULL;
+    char *error_str = NULL;
+    char *err_detail = NULL;
+    char *repo_id = NULL;
+    char *peer_id = NULL;
+    char *repo_name = NULL;
+    char *worktree = NULL;
+    char *tx_id = NULL;
+
+    g_object_get (obj,
+                  "state", &state,
+                  "error_str", &error_str,
+                  "err_detail", &err_detail,
+                  "repo_id", &repo_id,
+                  "peer_id", &peer_id,
+                  "repo_name", &repo_name,
+                  "worktree", &worktree,
+                  "tx_id", &tx_id,
+                  NULL);
+
+    task.state = QString::fromUtf8(state);
+    task.error_str = QString::fromUtf8(error_str);
+    task.error_detail = QString::fromUtf8(err_detail);
+    task.repo_id = QString::fromUtf8(repo_id);
+    task.peer_id = QString::fromUtf8(peer_id);
+    task.repo_name = QString::fromUtf8(repo_name);
+    task.worktree = QString::fromUtf8(worktree);
+    task.tx_id = QString::fromUtf8(tx_id);
+
+    task.block_done = 0;
+    task.block_total = 0;
+
+    task.checkout_done = 0;
+    task.checkout_total = 0;
+
+    g_free (state);
+    g_free (error_str);
+    g_free (err_detail);
+    g_free (repo_id);
+    g_free (peer_id);
+    g_free (repo_name);
+    g_free (worktree);
+    g_free (tx_id);
+
+    // task.translateStateInfo();
+
+    return task;
+}
+
+QString CloneTask::calcProgress(int done, int total)
+{
+    if (total == 0) {
+        return QString();
+    }
+
+    int percentage = done * 100 / total;
+
+    return QString().sprintf(" %d%%", percentage);
+}
+
+void CloneTask::translateStateInfo()
+{
+    if (state == "init") {
+        state_str = QObject::tr("initializing...");
+
+    } else if (state == "check server") {
+        state_str = QObject::tr("checking server info...");
+
+    } else if (state == "fetch") {
+        if (rt_state == "fs") {
+            state_str = QObject::tr("Downloading file list...");
+            if (fs_objects_total != 0) {
+                state_str += calcProgress(fs_objects_done, fs_objects_total);
+            }
+        } else if (rt_state == "data") {
+            state_str = QObject::tr("Downloading files...");
+            if (block_total != 0) {
+                state_str += calcProgress(block_done, block_total);
+            }
+        }
+
+    } else if (state == "done") {
+        state_str = QObject::tr("Done");
+
+    } else if (state == "canceling") {
+        state_str = QObject::tr("Canceling");
+
+    } else if (state == "canceled") {
+        state_str = QObject::tr("Canceled");
+
+    } else if (state == "error") {
+        if (error_str == "index") {
+            error_str = QObject::tr("Failed to index local files");
+
+        } else if (error_str == "check server") {
+            error_str = QObject::tr("Failed to check server information");
+        } else if (error_str == "checkout") {
+            error_str = QObject::tr("Failed to create local files");
+
+        } else if (error_str == "merge") {
+            error_str = QObject::tr("Failed to merge local file changes");
+
+        } else if (error_str == "password") {
+            error_str = QObject::tr("Incorrect password. Please download again");
+        } else if (error_str == "internal") {
+            error_str = QObject::tr("Internal error");
+        } else if (error_str == "Permission denied on server") {
+            error_str = QObject::tr("Permission denied on server. Please try to resync the library");
+        } else if (error_str == "Network error") {
+            error_str = QObject::tr("Network error");
+        } else if (error_str == "Cannot resolve proxy address") {
+            error_str = QObject::tr("Cannot resolve proxy address");
+        } else if (error_str == "Cannot resolve server address") {
+            error_str = QObject::tr("Cannot resolve server address");
+        } else if (error_str == "Cannot connect to server") {
+            error_str = QObject::tr("Cannot connect to server");
+        } else if (error_str == "Failed to establish secure connection") {
+            error_str = QObject::tr("Failed to establish secure connection. Please check server SSL certificate");
+        } else if (error_str == "Data transfer was interrupted") {
+            error_str = QObject::tr("Data transfer was interrupted. Please check network or firewall");
+        } else if (error_str == "Data transfer timed out") {
+            error_str = QObject::tr("Data transfer timed out. Please check network or firewall");
+        } else if (error_str == "Unhandled http redirect from server") {
+            error_str = QObject::tr("Unhandled http redirect from server. Please check server cofiguration");
+        } else if (error_str == "Server error") {
+            error_str = QObject::tr("Server error");
+        } else if (error_str == "Bad request") {
+            error_str = QObject::tr("Bad request");
+        } else if (error_str == "Internal data corrupt on the client") {
+            error_str = QObject::tr("Internal data corrupt on the client. Please try to resync the library");
+        } else if (error_str == "Not enough memory") {
+            error_str = QObject::tr("Not enough memory");
+        } else if (error_str == "Failed to write data on the client") {
+            error_str = QObject::tr("Failed to write data on the client. Please check disk space or folder permissions");
+        } else if (error_str == "Storage quota full") {
+            error_str = QObject::tr("Storage quota full");
+        } else if (error_str == "Files are locked by other application") {
+            error_str = QObject::tr("Files are locked by other application");
+        } else if (error_str == "Library deleted on server") {
+            error_str = QObject::tr("Library deleted on server");
+        } else if (error_str == "Library damaged on server") {
+            error_str = QObject::tr("Library damaged on server");
+        }
+    } else if (state == "connect") {
+        state_str = QObject::tr("connecting server...");
+
+    } else if (state == "index") {
+        state_str = QObject::tr("indexing files...");
+
+    } else if (state == "checkout") {
+        state_str = QObject::tr("Creating folder...");
+        if (checkout_total != 0) {
+            state_str += calcProgress(checkout_done, checkout_total);
+        }
+
+    } else if (state == "merge") {
+        state_str = QObject::tr("Merge file changes...");
+    }
+
+    if (state != "error" || error_str == "ok") {
+        error_str = "";
+    }
+}
+
+bool CloneTask::isCancelable() const
+{
+    QStringList list;
+    list << "init" << "connect" << "index" << "fetch" << "error";
+    return list.contains(state);
+}
+
+
+bool CloneTask::isRemovable() const
+{
+    QStringList list;
+    list << "done" << "canceled";
+    return list.contains(state);
+}
+
+bool CloneTask::isDisplayable() const
+{
+    return state != "canceled" && state != "done";
+}
diff --git a/src/rpc/clone-task.h b/src/rpc/clone-task.h
new file mode 100644 (file)
index 0000000..28404f6
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef SEAFILE_CLIENT_RPC_CLONE_TASK_H
+#define SEAFILE_CLIENT_RPC_CLONE_TASK_H
+
+#include <QString>
+#include <QMetaType>
+
+struct _GObject;
+
+class CloneTask {
+public:
+    QString repo_id;
+    QString repo_name;
+    QString worktree;
+    QString state;
+    QString rt_state;
+    QString error_str;
+    QString error_detail;
+    QString peer_id;
+    QString tx_id;
+
+    QString state_str;
+    qint64 block_done;
+    qint64 block_total;
+
+    int fs_objects_done;
+    int fs_objects_total;
+
+    int checkout_done;
+    int checkout_total;
+
+    static CloneTask fromGObject(_GObject *obj);
+
+    void translateStateInfo();
+
+    bool isCancelable() const;
+    bool isRemovable() const;
+    bool isDisplayable() const;
+    bool isSuccessful() const { return state == "done"; }
+
+    bool isValid() const { return !repo_id.isEmpty(); }
+
+    bool operator==(const CloneTask& rhs) const {
+        return repo_id == rhs.repo_id
+            && repo_name == rhs.repo_name
+            && worktree == rhs.worktree
+            && state_str == rhs.state_str
+            && error_str == rhs.error_str
+            && error_detail == rhs.error_detail;
+    }
+
+    bool operator!=(const CloneTask& rhs) const {
+        return !(*this == rhs);
+    }
+
+private:
+    QString calcProgress(int done, int total);
+};
+
+#endif // SEAFILE_CLIENT_RPC_CLONE_TASK_H
diff --git a/src/rpc/local-repo.cpp b/src/rpc/local-repo.cpp
new file mode 100644 (file)
index 0000000..32c4354
--- /dev/null
@@ -0,0 +1,311 @@
+#include <glib-object.h>
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "local-repo.h"
+
+LocalRepo LocalRepo::fromGObject(GObject *obj)
+{
+    char *id = NULL;
+    char *name = NULL;
+    char *desc = NULL;
+    char *worktree = NULL;
+    char *relay_id = NULL;
+
+    gboolean encrypted;
+    gboolean auto_sync;
+    gboolean worktree_invalid;
+    gint64 last_sync_time;
+    int version;
+
+    g_object_get (obj,
+                  "id", &id,
+                  "name", &name,
+                  "desc", &desc,
+                  "encrypted", &encrypted,
+                  "worktree", &worktree,
+                  "auto-sync", &auto_sync,
+                  "last-sync-time", &last_sync_time,
+                  "worktree-invalid", &worktree_invalid,
+                  "relay-id", &relay_id,
+                  "version", &version,
+                  NULL);
+
+    LocalRepo repo;
+    repo.id = QString::fromUtf8(id);
+    repo.name = QString::fromUtf8(name);
+    repo.description = QString::fromUtf8(desc);
+    repo.worktree = QString::fromUtf8(worktree);
+    repo.encrypted = encrypted;
+    repo.auto_sync = auto_sync;
+    repo.last_sync_time = last_sync_time;
+    repo.worktree_invalid = worktree_invalid;
+    repo.relay_id = relay_id;
+    repo.version = version;
+
+    g_free (id);
+    g_free (name);
+    g_free (desc);
+    g_free (worktree);
+    g_free (relay_id);
+
+    return repo;
+}
+
+void LocalRepo::setSyncInfo(const QString &state, const QString &error, const QString &err_detail)
+{
+    // qWarning("error: %s\n", toCStr(error));
+    // qWarning("state: %s\n", toCStr(state));
+    if (error.length() > 0) {
+        translateSyncError(error);
+        if (err_detail.length() > 0)
+            translateSyncErrDetail(err_detail);
+    } else {
+        translateSyncState(state);
+    }
+}
+
+void LocalRepo::translateSyncState(const QString &status)
+{
+    if (status == "synchronized") {
+        sync_state_str = QObject::tr("synchronized");
+        sync_state = SYNC_STATE_DONE;
+
+    } else if (status == "committing") {
+        sync_state_str = QObject::tr("indexing files");
+        sync_state = SYNC_STATE_ING;
+        has_data_transfer = false;
+
+    } else if (status == "initializing") {
+        sync_state_str = QObject::tr("sync initializing");
+        sync_state = SYNC_STATE_INIT;
+
+    } else if (status == "downloading") {
+        sync_state_str = QObject::tr("downloading");
+        sync_state = SYNC_STATE_ING;
+        has_data_transfer = true;
+
+    } else if (status == "uploading") {
+        sync_state_str = QObject::tr("uploading");
+        sync_state = SYNC_STATE_ING;
+        has_data_transfer = true;
+
+    } else if (status == "merging") {
+        sync_state_str = QObject::tr("sync merging");
+        sync_state = SYNC_STATE_ING;
+        has_data_transfer = false;
+
+    } else if (status == "waiting for sync") {
+        sync_state_str = QObject::tr("waiting for sync");
+        sync_state = SYNC_STATE_WAITING;
+
+    } else if (status == "relay not connected") {
+        sync_state_str = QObject::tr("server not connected");
+        sync_state = SYNC_STATE_WAITING;
+
+    } else if (status == "relay authenticating") {
+        sync_state_str = QObject::tr("server authenticating");
+        sync_state = SYNC_STATE_WAITING;
+
+    } else if (status == "auto sync is turned off") {
+        sync_state_str = QObject::tr("auto sync is turned off");
+        sync_state = SYNC_STATE_DISABLED;
+
+    } else if (status == "cancel pending") {
+        sync_state_str = QObject::tr("sync initializing");
+        sync_state = SYNC_STATE_INIT;
+
+    } else {
+        qWarning("unknown sync status: %s\n", toCStr(status));
+        sync_state_str = QObject::tr("unknown");
+        sync_state = SYNC_STATE_UNKNOWN;
+    }
+
+    if (!auto_sync && sync_state != SYNC_STATE_ING) {
+        sync_state_str = QObject::tr("auto sync is turned off");
+        sync_state = SYNC_STATE_DISABLED;
+        return;
+    }
+}
+
+void LocalRepo::translateSyncError(const QString &error)
+{
+    sync_state = SYNC_STATE_ERROR;
+
+    if (error == "relay not connected") {
+        sync_error_str = QObject::tr("server not connected");
+
+    } else if (error == "Server has been removed") {
+        sync_error_str = QObject::tr("Server has been removed");
+
+    } else if (error == "You have not login to the server") {
+        sync_error_str = QObject::tr("You have not logged in to the server");
+
+    } else if (error == "You do not have permission to access this repo") {
+        sync_error_str = QObject::tr("You do not have permission to access this library");
+
+    } else if (error == "The storage space of the repo owner has been used up") {
+        sync_error_str = QObject::tr("The storage space of the library owner has been used up");
+
+    } else if (error == "Remote service is not available") {
+        sync_error_str = QObject::tr("Remote service is not available");
+
+    } else if (error == "Access denied to service. Please check your registration on relay.") {
+        sync_error_str = QObject::tr("Access denied to service");
+
+    } else if (error == "Internal data corrupted.") {
+        sync_error_str = QObject::tr("Internal data corrupted");
+
+    } else if (error == "Failed to start upload.") {
+        sync_error_str = QObject::tr("Failed to start upload");
+
+    } else if (error == "Error occurred in upload.") {
+        sync_error_str = QObject::tr("Error occurred in upload");
+
+    } else if (error == "Failed to start download.") {
+        sync_error_str = QObject::tr("Failed to start download");
+
+    } else if (error == "Error occurred in download.") {
+        sync_error_str = QObject::tr("Error occurred in download");
+
+    } else if (error == "No such repo on relay.") {
+        sync_error_str = QObject::tr("Library is deleted on server");
+
+    } else if (error == "Repo is damaged on relay.") {
+        sync_error_str = QObject::tr("Library is damaged on server");
+
+    } else if (error == "Conflict in merge.") {
+        sync_error_str = QObject::tr("Conflict in merge");
+
+    } else if (error == "Server version is too old.") {
+        sync_error_str = QObject::tr("Server version is too old");
+
+    } else if (error == "invalid worktree") {
+        sync_error_str = QObject::tr("Error when accessing the local folder");
+
+    } else if (error == "Unknown error." || error == "Unknown error") {
+        sync_error_str = QObject::tr("Unknown error");
+
+    } else if (error == "Storage quota full") {
+        sync_error_str = QObject::tr("The storage quota has been used up");
+
+    } else if (error == "Service on remote server is not available") {
+        sync_error_str = QObject::tr("Internal server error");
+
+    } else if (error == "Access denied to service. Please check your registration on server.") {
+        sync_error_str = QObject::tr("Access denied to service");
+
+    } else if (error == "Transfer protocol outdated. You need to upgrade seafile.") {
+        sync_error_str = QObject::tr("Your %1 client is too old").arg(getBrand());
+
+    } else if (error == "Internal error when preparing upload") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+
+    } else if (error == "Internal error when preparing download") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+
+    } else if (error == "No permission to access remote library") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+
+    } else if (error == "Library doesn't exist on the remote end") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+
+    } else if (error == "Internal error when starting to send revision information") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Internal error when starting to get revision information") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Failed to upload revision information to remote library") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Failed to get revision information from remote library") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Internal error when starting to send file information") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Internal error when starting to get file information") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Incomplete file information in the local library") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Failed to upload file information to remote library") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Failed to get file information from remote library") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Internal error when starting to update remote library") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Others have concurrent updates to the remote library. You need to sync again.") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Server failed to check storage quota") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Incomplete revision information in the local library") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Failed to compare data to server.") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Failed to get block server list.") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Failed to start block transfer client.") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Failed to upload blocks.") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+    } else if (error == "Failed to download blocks.") {
+        sync_error_str = QObject::tr("Failed to sync this library");
+
+    } else if (error == "Files are locked by other application") {
+        sync_error_str = QObject::tr("Files are locked by other application");
+    } else {
+        sync_error_str = error;
+    }
+}
+
+void LocalRepo::translateSyncErrDetail(const QString &err_detail)
+{
+    if (err_detail == "Permission denied on server") {
+        sync_error_detail = QObject::tr("Permission denied on server. Please try to resync the library");
+    } else if (err_detail == "Network error") {
+        sync_error_detail = QObject::tr("Network error");
+    } else if (err_detail == "Cannot resolve proxy address") {
+        sync_error_detail = QObject::tr("Cannot resolve proxy address");
+    } else if (err_detail == "Cannot resolve server address") {
+        sync_error_detail = QObject::tr("Cannot resolve server address");
+    } else if (err_detail == "Cannot connect to server") {
+        sync_error_detail = QObject::tr("Cannot connect to server");
+    } else if (err_detail == "Failed to establish secure connection") {
+        sync_error_detail = QObject::tr("Failed to establish secure connection. Please check server SSL certificate");
+    } else if (err_detail == "Data transfer was interrupted") {
+        sync_error_detail = QObject::tr("Data transfer was interrupted. Please check network or firewall");
+    } else if (err_detail == "Data transfer timed out") {
+        sync_error_detail = QObject::tr("Data transfer timed out. Please check network or firewall");
+    } else if (err_detail == "Unhandled http redirect from server") {
+        sync_error_detail = QObject::tr("Unhandled http redirect from server. Please check server cofiguration");
+    } else if (err_detail == "Server error") {
+        sync_error_detail = QObject::tr("Server error");
+    } else if (err_detail == "Bad request") {
+        sync_error_detail = QObject::tr("Bad request");
+    } else if (err_detail == "Internal data corrupt on the client") {
+        sync_error_detail = QObject::tr("Internal data corrupt on the client. Please try to resync the library");
+    } else if (err_detail == "Not enough memory") {
+        sync_error_detail = QObject::tr("Not enough memory");
+    } else if (err_detail == "Failed to write data on the client") {
+        sync_error_detail = QObject::tr("Failed to write data on the client. Please check disk space or folder permissions");
+    } else if (err_detail == "Storage quota full") {
+        sync_error_detail = QObject::tr("Storage quota full");
+    } else if (err_detail == "Files are locked by other application") {
+        sync_error_detail = QObject::tr("Files are locked by other application");
+    } else if (err_detail == "Library deleted on server") {
+        sync_error_detail = QObject::tr("Library deleted on server");
+    } else if (err_detail == "Library damaged on server") {
+        sync_error_detail = QObject::tr("Library damaged on server");
+    } else if (err_detail == "File is locked by another user") {
+        sync_error_detail = QObject::tr("File is locked by another user");
+    } else if (err_detail == "Do not have write permission to the library") {
+        sync_error_detail = QObject::tr("Do not have write permission to the library");
+    } else if (err_detail == "Do not have permission to sync the library") {
+        sync_error_detail = QObject::tr("Do not have permission to sync the library");
+    } else {
+        sync_error_detail = err_detail;
+    }
+
+    // printf ("sync error detail set to '%s'\n", sync_error_detail.toUtf8().data());
+}
+
+QString LocalRepo::getErrorString() const
+{
+    return sync_error_detail.isEmpty() ? sync_error_str : sync_error_detail;
+}
diff --git a/src/rpc/local-repo.h b/src/rpc/local-repo.h
new file mode 100644 (file)
index 0000000..0064179
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef SEAFILE_CLIENT_LOCAL_REPO_H
+#define SEAFILE_CLIENT_LOCAL_REPO_H
+
+#include <QString>
+#include <QIcon>
+#include <QMetaType>
+
+#include "account.h"
+
+struct _GObject;
+
+/**
+ * Repo Information from local seaf-daemon
+ */
+class LocalRepo {
+public:
+    enum SyncState {
+        SYNC_STATE_DISABLED,
+        SYNC_STATE_WAITING,
+        SYNC_STATE_INIT,
+        SYNC_STATE_ING,
+        SYNC_STATE_DONE,
+        SYNC_STATE_ERROR,
+        SYNC_STATE_UNKNOWN,
+    };
+
+    QString id;
+    QString name;
+    QString description;
+    QString worktree;
+    bool encrypted;
+    bool auto_sync;
+    bool worktree_invalid;
+    int version;
+    QString relay_id;
+    Account account;
+
+    qint64 last_sync_time;
+    SyncState sync_state;
+    QString rt_state;
+    QString sync_state_str;
+    QString sync_error_str;
+    QString sync_error_detail;
+    int transfer_percentage;
+    int transfer_rate;
+    bool has_data_transfer;
+
+    LocalRepo()
+        : encrypted(false),
+        auto_sync(false),
+        worktree_invalid(false),
+        version(0),
+        last_sync_time(0),
+        sync_state(SYNC_STATE_DISABLED),
+        has_data_transfer(false)
+    {
+    }
+
+    static LocalRepo fromGObject(_GObject *obj);
+
+    bool operator==(const LocalRepo& rhs) const {
+        return id == rhs.id
+            && name == rhs.name
+            && description == rhs.description
+            && worktree == rhs.worktree
+            && encrypted == rhs.encrypted
+            && auto_sync == rhs.auto_sync
+            && sync_state == rhs.sync_state
+            && rt_state == rhs.rt_state
+            && sync_state_str == rhs.sync_state_str
+            && sync_error_str == rhs.sync_error_str
+            && transfer_rate == rhs.transfer_rate
+            && transfer_percentage == rhs.transfer_percentage;
+    }
+
+    bool operator!=(const LocalRepo& rhs) const {
+        return !(*this == rhs);
+    }
+
+    bool isValid() const { return id.length() > 0; }
+
+    QString getErrorString() const;
+
+    void setSyncInfo(const QString &state, const QString &error = QString(), const QString &err_detail = QString());
+
+private:
+    void translateSyncError(const QString &error);
+    void translateSyncState(const QString &state);
+    void translateSyncErrDetail(const QString &err_detail);
+};
+
+Q_DECLARE_METATYPE(LocalRepo)
+
+#endif // SEAFILE_CLIENT_LOCAL_REPO_H
diff --git a/src/rpc/rpc-client.cpp b/src/rpc/rpc-client.cpp
new file mode 100644 (file)
index 0000000..99679b1
--- /dev/null
@@ -0,0 +1,1034 @@
+extern "C" {
+
+#include <searpc-client.h>
+#include <searpc-named-pipe-transport.h>
+
+#include <searpc.h>
+#include <seafile/seafile.h>
+#include <seafile/seafile-object.h>
+
+}
+
+#include <QtDebug>
+#include <QMutexLocker>
+
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "settings-mgr.h"
+
+#include "utils/utils.h"
+#include "local-repo.h"
+#include "clone-task.h"
+#include "sync-error.h"
+#include "api/commit-details.h"
+
+#if defined(Q_OS_WIN32)
+  #include "utils/utils-win.h"
+#endif
+
+#include "rpc-client.h"
+
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+const char *kSeafileSockName = "\\\\.\\pipe\\seafile_";
+#else
+const char *kSeafileSockName = "seafile.sock";
+#endif
+const char *kSeafileRpcService = "seafile-rpcserver";
+const char *kSeafileThreadedRpcService = "seafile-threaded-rpcserver";
+
+QString getSeafileRpcPipePath()
+{
+#if defined(Q_OS_WIN32)
+    return utils::win::getLocalPipeName(kSeafileSockName).c_str();
+#else
+    return QDir(seafApplet->configurator()->seafileDir()).filePath(kSeafileSockName);
+#endif
+}
+
+SearpcClient *createSearpcClientWithPipeTransport(const char *rpc_service)
+{
+    SearpcNamedPipeClient *pipe_client;
+    pipe_client = searpc_create_named_pipe_client(toCStr(getSeafileRpcPipePath()));
+    int ret = searpc_named_pipe_client_connect(pipe_client);
+    SearpcClient *c = searpc_client_with_named_pipe_transport(pipe_client, rpc_service);
+    if (ret < 0) {
+        searpc_free_client_with_pipe_transport(c);
+        return nullptr;
+    }
+    return c;
+}
+
+} // namespace
+
+SeafileRpcClient::SeafileRpcClient()
+    : connected_(false),
+      seafile_rpc_client_(nullptr),
+      seafile_threaded_rpc_client_(nullptr)
+{
+}
+
+SeafileRpcClient::~SeafileRpcClient()
+{
+    if (seafile_rpc_client_) {
+        searpc_free_client_with_pipe_transport(seafile_rpc_client_);
+        seafile_rpc_client_ = nullptr;
+    }
+    if (seafile_threaded_rpc_client_) {
+        searpc_free_client_with_pipe_transport(seafile_threaded_rpc_client_);
+        seafile_threaded_rpc_client_ = nullptr;
+    }
+}
+
+bool SeafileRpcClient::connectDaemon(bool exit_on_error)
+{
+    int retry = 0;
+    while (true) {
+        seafile_rpc_client_ = createSearpcClientWithPipeTransport(kSeafileRpcService);
+        if (!seafile_rpc_client_) {
+            if (retry++ > 20) {
+                if (exit_on_error) {
+                    seafApplet->errorAndExit(tr("internal error: failed to connect to daemon"));
+                }
+                return false;
+            } else {
+                g_usleep(500000);
+            }
+        } else {
+            // Create the searpc client for threaded rpc calls
+            seafile_threaded_rpc_client_ = createSearpcClientWithPipeTransport(kSeafileThreadedRpcService);
+            if (!seafile_threaded_rpc_client_) {
+                searpc_free_client_with_pipe_transport(seafile_rpc_client_);
+                seafile_rpc_client_ = nullptr;
+                continue;
+            }
+            break;
+        }
+    }
+
+    connected_ = true;
+    qWarning("[Rpc Client] connected to daemon");
+    return true;
+}
+
+int SeafileRpcClient::listLocalRepos(std::vector<LocalRepo> *result)
+{
+    GError *error = NULL;
+    GList *repos = seafile_get_repo_list(seafile_rpc_client_, 0, 0, &error);
+    if (error != NULL) {
+        qWarning("failed to get repo list: %s\n", error->message);
+        g_error_free(error);
+        return -1;
+    }
+
+    result->clear();
+    for (GList *ptr = repos; ptr; ptr = ptr->next) {
+        result->push_back(LocalRepo::fromGObject((GObject*)ptr->data));
+    }
+
+    g_list_foreach (repos, (GFunc)g_object_unref, NULL);
+    g_list_free (repos);
+
+    return 0;
+}
+
+int SeafileRpcClient::setAutoSync(bool autoSync)
+{
+    GError *error = NULL;
+    int ret;
+    if (autoSync) {
+        ret = searpc_client_call__int (seafile_rpc_client_,
+                                       "seafile_enable_auto_sync",
+                                       &error, 0);
+    } else {
+        ret = searpc_client_call__int (seafile_rpc_client_,
+                                       "seafile_disable_auto_sync",
+                                       &error, 0);
+    }
+
+    if (error) {
+        qWarning("failed to set auto_sync: %s\n", error->message);
+        g_error_free(error);
+    }
+
+    return ret;
+}
+
+int SeafileRpcClient::downloadRepo(const QString& id,
+                                   int repo_version, const QString& relayId,
+                                   const QString& name, const QString& wt,
+                                   const QString& token, const QString& passwd,
+                                   const QString& magic, const QString& peerAddr,
+                                   const QString& port, const QString& email,
+                                   const QString& random_key, int enc_version,
+                                   const QString& more_info,
+                                   QString *error_ret)
+{
+    GError *error = NULL;
+    char *ret = searpc_client_call__string(
+        seafile_rpc_client_,
+        "seafile_download",
+        &error, 14,
+        "string", toCStr(id),
+        "int", repo_version,
+        "string", toCStr(relayId),
+        "string", toCStr(name),
+        "string", toCStr(wt),
+        "string", toCStr(token),
+        "string", toCStr(passwd),
+        "string", toCStr(magic),
+        "string", toCStr(peerAddr),
+        "string", toCStr(port),
+        "string", toCStr(email),
+        "string", toCStr(random_key),
+        "int", enc_version,
+        "string", toCStr(more_info));
+
+    if (error != NULL) {
+        if (error_ret) {
+            *error_ret = error->message;
+        }
+        g_error_free(error);
+        return -1;
+    }
+
+    g_free(ret);
+    return 0;
+}
+
+int SeafileRpcClient::cloneRepo(const QString& id,
+                                int repo_version, const QString& relayId,
+                                const QString &name, const QString &wt,
+                                const QString &token, const QString &passwd,
+                                const QString &magic, const QString &peerAddr,
+                                const QString &port, const QString &email,
+                                const QString& random_key, int enc_version,
+                                const QString& more_info,
+                                QString *error_ret)
+{
+    GError *error = NULL;
+    char *ret = searpc_client_call__string(
+        seafile_rpc_client_,
+        "seafile_clone",
+        &error, 14,
+        "string", toCStr(id),
+        "int", repo_version,
+        "string", toCStr(relayId),
+        "string", toCStr(name),
+        "string", toCStr(wt),
+        "string", toCStr(token),
+        "string", toCStr(passwd),
+        "string", toCStr(magic),
+        "string", toCStr(peerAddr),
+        "string", toCStr(port),
+        "string", toCStr(email),
+        "string", toCStr(random_key),
+        "int", enc_version,
+        "string", toCStr(more_info));
+
+    if (error != NULL) {
+        if (error_ret) {
+            // copy string
+            *error_ret = error->message;
+        }
+        g_error_free(error);
+        return -1;
+    }
+
+    g_free(ret);
+    return 0;
+}
+
+int SeafileRpcClient::getLocalRepo(const QString& repo_id, LocalRepo *repo)
+{
+    GError *error = NULL;
+    GObject *obj = searpc_client_call__object(
+        seafile_rpc_client_,
+        "seafile_get_repo",
+        SEAFILE_TYPE_REPO,
+        &error, 1,
+        "string", toCStr(repo_id));
+
+    if (error != NULL) {
+        g_error_free(error);
+        return -1;
+    }
+
+    if (obj == NULL) {
+        return -1;
+    }
+
+    *repo = LocalRepo::fromGObject(obj);
+    g_object_unref(obj);
+
+    getSyncStatus(*repo);
+    return 0;
+}
+
+int SeafileRpcClient::seafileGetConfig(const QString &key,
+                                       QString *value)
+{
+    GError *error = NULL;
+    char *ret = searpc_client_call__string (seafile_rpc_client_,
+                                            "seafile_get_config", &error,
+                                            1, "string", toCStr(key));
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+    *value = QString::fromUtf8(ret);
+
+    g_free (ret);
+    return 0;
+}
+
+int SeafileRpcClient::seafileGetConfigInt(const QString &key,
+                                          int *value)
+{
+    GError *error = NULL;
+    *value = searpc_client_call__int (seafile_rpc_client_,
+                                      "seafile_get_config_int", &error,
+                                      1, "string", toCStr(key));
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+    return 0;
+}
+
+int SeafileRpcClient::seafileSetConfig(const QString &key, const QString &value)
+{
+    // printf ("set config: %s = %s\n", toCStr(key), toCStr(value));
+    GError *error = NULL;
+    searpc_client_call__int (seafile_rpc_client_,
+                             "seafile_set_config", &error,
+                             2, "string", toCStr(key),
+                             "string", toCStr(value));
+    if (error) {
+        qWarning("Unable to set config value %s", key.toUtf8().data());
+        g_error_free(error);
+        return -1;
+    }
+    return 0;
+}
+
+int SeafileRpcClient::setUploadRateLimit(int limit)
+{
+    return setRateLimit(UPLOAD, limit);
+}
+
+int SeafileRpcClient::setDownloadRateLimit(int limit)
+{
+    return setRateLimit(DOWNLOAD, limit);
+}
+
+int SeafileRpcClient::setRateLimit(Direction direction, int limit)
+{
+    GError *error = NULL;
+    const char *rpc = direction == UPLOAD ? "seafile_set_upload_rate_limit"
+                                          : "seafile_set_download_rate_limit";
+    searpc_client_call__int (seafile_rpc_client_,
+                             rpc, &error,
+                             1, "int", limit);
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+    return 0;
+}
+
+int SeafileRpcClient::seafileSetConfigInt(const QString &key, int value)
+{
+    // printf ("set config: %s = %d\n", toCStr(key), value);
+    GError *error = NULL;
+    searpc_client_call__int (seafile_rpc_client_,
+                             "seafile_set_config_int", &error,
+                             2, "string", toCStr(key),
+                             "int", value);
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+    return 0;
+}
+
+bool SeafileRpcClient::hasLocalRepo(const QString& repo_id)
+{
+    LocalRepo repo;
+    if (getLocalRepo(repo_id, &repo) < 0) {
+        return false;
+    }
+
+    return true;
+}
+
+void SeafileRpcClient::getSyncStatus(LocalRepo &repo)
+{
+    if (repo.worktree_invalid) {
+        repo.setSyncInfo("error", "invalid worktree");
+        return;
+    }
+
+    GError *error = NULL;
+    SeafileSyncTask *task = (SeafileSyncTask *)
+        searpc_client_call__object (seafile_rpc_client_,
+                                    "seafile_get_repo_sync_task",
+                                    SEAFILE_TYPE_SYNC_TASK,
+                                    &error, 1,
+                                    "string", toCStr(repo.id));
+    if (error) {
+        repo.setSyncInfo("unknown");
+        g_error_free(error);
+        return;
+    }
+
+    if (!task) {
+        repo.setSyncInfo("waiting for sync");
+        return;
+    }
+
+    char *state = NULL;
+    char *err = NULL;
+    char *err_detail = NULL;
+    g_object_get(task, "state", &state, "error", &err, "err_detail", &err_detail, NULL);
+
+    // seaf-daemon would retry three times for errors like quota/permission
+    // before setting the "state" field to "error", but the GUI should display
+    // the error from the beginning.
+    if (err != NULL && strlen(err) > 0 && strcmp(err, "Success") != 0) {
+        state = g_strdup("error");
+    }
+
+    repo.setSyncInfo(state,
+                     g_strcmp0(state, "error") == 0 ? err : NULL,
+                     err_detail);
+
+    if (repo.sync_state == LocalRepo::SYNC_STATE_ING) {
+        getRepoTransferInfo(repo.id, &repo.transfer_rate, &repo.transfer_percentage, &repo.rt_state);
+    }
+
+    // When uploading fs objects, we show it as "uploading files list" and don't
+    // show the current precentage
+    if (QString(state) == "uploading" && repo.rt_state == "fs") {
+        repo.sync_state_str = QObject::tr("uploading file list");
+        repo.has_data_transfer = false;
+    }
+
+    g_free (state);
+    g_free (err);
+    g_free (err_detail);
+    g_object_unref(task);
+}
+
+int SeafileRpcClient::getCloneTasks(std::vector<CloneTask> *tasks)
+{
+    GError *error = NULL;
+    GList *objlist = searpc_client_call__objlist(
+        seafile_rpc_client_,
+        "seafile_get_clone_tasks",
+        SEAFILE_TYPE_CLONE_TASK,
+        &error, 0);
+
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+
+    for (GList *ptr = objlist; ptr; ptr = ptr->next) {
+        CloneTask task = CloneTask::fromGObject((GObject *)ptr->data);
+
+        if (task.state == "fetch") {
+            getTransferDetail(&task);
+        } else if (task.state == "error") {
+            if (!task.error_detail.isNull())
+                task.error_str = task.error_detail;
+        }
+        task.translateStateInfo();
+        tasks->push_back(task);
+    }
+
+    g_list_foreach (objlist, (GFunc)g_object_unref, NULL);
+    g_list_free (objlist);
+
+    return 0;
+}
+
+void SeafileRpcClient::getTransferDetail(CloneTask* task)
+{
+    GError *error = NULL;
+    GObject *obj = searpc_client_call__object(
+        seafile_rpc_client_,
+        "seafile_find_transfer_task",
+        SEAFILE_TYPE_TASK,
+        &error, 1,
+        "string", toCStr(task->repo_id));
+
+    if (error != NULL) {
+        g_error_free(error);
+        return;
+    }
+
+    if (obj == NULL) {
+        return;
+    }
+
+    if (task->state == "fetch") {
+        char *rt_state = NULL;
+        g_object_get (obj, "rt_state", &rt_state, NULL);
+        task->rt_state = rt_state;
+        g_free (rt_state);
+
+        if (task->rt_state == "data") {
+            qint64 block_done = 0;
+            qint64 block_total = 0;
+
+            g_object_get (obj,
+                          "block_done", &block_done,
+                          "block_total", &block_total,
+                          NULL);
+
+            task->block_done = block_done;
+            task->block_total = block_total;
+        } else if (task->rt_state == "fs") {
+            int fs_objects_done = 0;
+            int fs_objects_total = 0;
+
+            g_object_get (obj,
+                          "fs_objects_done", &fs_objects_done,
+                          "fs_objects_total", &fs_objects_total,
+                          NULL);
+
+            task->fs_objects_done = fs_objects_done;
+            task->fs_objects_total = fs_objects_total;
+        }
+    }
+
+    g_object_unref (obj);
+}
+
+int SeafileRpcClient::cancelCloneTask(const QString& repo_id, QString *err)
+{
+    GError *error = NULL;
+    int ret = searpc_client_call__int (seafile_rpc_client_,
+                                       "seafile_cancel_clone_task",
+                                       &error, 1,
+                                       "string", toCStr(repo_id));
+
+    if (ret < 0) {
+        if (err) {
+            *err = error ? error->message : tr("Unknown error");
+        }
+        if (error) {
+            g_error_free(error);
+        }
+    }
+
+    return ret;
+}
+
+int SeafileRpcClient::removeCloneTask(const QString& repo_id, QString *err)
+{
+    GError *error = NULL;
+    int ret = searpc_client_call__int (seafile_rpc_client_,
+                                       "seafile_remove_clone_task",
+                                       &error, 1,
+                                       "string", toCStr(repo_id));
+
+    if (ret < 0) {
+        if (err) {
+            *err = error ? error->message : tr("Unknown error");
+        }
+        if (error) {
+            g_error_free(error);
+        }
+    }
+
+    return ret;
+}
+
+int SeafileRpcClient::getCloneTasksCount(int *count)
+{
+    GError *error = NULL;
+    GList *objlist = searpc_client_call__objlist(
+        seafile_rpc_client_,
+        "seafile_get_clone_tasks",
+        SEAFILE_TYPE_CLONE_TASK,
+        &error, 0);
+
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+
+    if (count) {
+        *count = g_list_length(objlist);
+    }
+
+    g_list_foreach (objlist, (GFunc)g_object_unref, NULL);
+    g_list_free (objlist);
+
+    return 0;
+}
+
+int SeafileRpcClient::unsyncReposByAccount(const QString& server_addr,
+                                           const QString& email,
+                                           QString *err)
+{
+    GError *error = NULL;
+    int ret =  searpc_client_call__int (seafile_rpc_client_,
+                                        "seafile_unsync_repos_by_account",
+                                        &error, 2,
+                                        "string", toCStr(server_addr),
+                                        "string", toCStr(email));
+
+    if (ret < 0 && err) {
+        if (error) {
+            *err = QString::fromUtf8(error->message);
+            g_error_free(error);
+        } else {
+            *err = tr("Unknown error");
+        }
+    }
+
+    return ret;
+}
+
+int SeafileRpcClient::getDownloadRate(int *rate)
+{
+    GError *error = NULL;
+    int ret = searpc_client_call__int (seafile_rpc_client_,
+                                       "seafile_get_download_rate",
+                                       &error, 0);
+
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+
+    *rate = ret;
+    return 0;
+}
+
+int SeafileRpcClient::getUploadRate(int *rate)
+{
+    GError *error = NULL;
+    int ret = searpc_client_call__int (seafile_rpc_client_,
+                                       "seafile_get_upload_rate",
+                                       &error, 0);
+
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+
+    *rate = ret;
+    return 0;
+}
+
+
+void SeafileRpcClient::setRepoAutoSync(const QString& repo_id, bool auto_sync)
+{
+    GError *error = NULL;
+    searpc_client_call__int(seafile_rpc_client_,
+                            "seafile_set_repo_property",
+                            &error, 3,
+                            "string", toCStr(repo_id),
+                            "string", "auto-sync",
+                            "string", auto_sync ? "true" : "false");
+    if (error) {
+        g_error_free(error);
+    }
+}
+
+int SeafileRpcClient::unsync(const QString& repo_id)
+{
+    GError *error = NULL;
+    int ret = searpc_client_call__int(seafile_rpc_client_,
+                                      "seafile_destroy_repo",
+                                      &error, 1,
+                                      "string", toCStr(repo_id));
+    if (error) {
+        g_error_free(error);
+    }
+
+    return ret;
+}
+
+int SeafileRpcClient::getRepoTransferInfo(const QString& repo_id, int *rate, int *percent, QString *rt_state)
+{
+    GError *error = NULL;
+    GObject *task = searpc_client_call__object (seafile_rpc_client_,
+                                                "seafile_find_transfer_task",
+                                                SEAFILE_TYPE_TASK,
+                                                &error, 1,
+                                                "string", toCStr(repo_id));
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+
+    if (!task) {
+        return -1;
+    }
+
+    int64_t finished = 0;
+    int64_t total = 0;
+    char *rt = nullptr;
+    g_object_get (task,
+                  "rate", rate,
+                  "block_total", &total,
+                  "block_done", &finished,
+                  "rt_state", &rt,
+                  NULL);
+
+    if (total == 0) {
+        *percent = 0;
+    } else {
+        *percent = (int)(100 * finished / total);
+    }
+
+    if (rt) {
+        if (rt_state) {
+            *rt_state = rt;
+        }
+        g_free(rt);
+    }
+
+    g_object_unref(task);
+
+    return 0;
+}
+
+void SeafileRpcClient::syncRepoImmediately(const QString& repo_id)
+{
+    searpc_client_call__int (seafile_rpc_client_,
+                             "seafile_sync", NULL,
+                             2,
+                             "string", toCStr(repo_id),
+                             "string", NULL);
+}
+
+int SeafileRpcClient::checkPathForClone(const QString& path, QString *err_msg)
+{
+    GError *error = NULL;
+    int ret = searpc_client_call__int (seafile_rpc_client_,
+                                       "seafile_check_path_for_clone", &error,
+                                       1, "string", toCStr(path));
+
+    if (ret == 0) {
+        return 0;
+    }
+
+    if (err_msg) {
+        *err_msg = QString::fromUtf8(error->message);
+    }
+
+    g_error_free(error);
+    return -1;
+}
+
+QString SeafileRpcClient::getCcnetPeerId()
+{
+    // TODO: Get the device id now that ccnet is removed.
+    return "";
+}
+
+int SeafileRpcClient::updateReposServerHost(const QString& old_host,
+                                            const QString& new_host,
+                                            const QString& new_server_url,
+                                            QString *err)
+{
+    GError *error = NULL;
+    int ret =  searpc_client_call__int (seafile_rpc_client_,
+                                        "seafile_update_repos_server_host",
+                                        &error, 3,
+                                        "string", toCStr(old_host),
+                                        "string", toCStr(new_host),
+                                        "string", toCStr(new_server_url));
+
+    if (ret < 0) {
+        if (error) {
+            *err = QString::fromUtf8(error->message);
+            g_error_free(error);
+        } else {
+            *err = tr("Unknown error");
+        }
+    }
+
+    return ret;
+}
+
+int SeafileRpcClient::getRepoProperty(const QString &repo_id,
+                                      const QString& name,
+                                      QString *value)
+{
+    GError *error = NULL;
+    char *ret = searpc_client_call__string (
+        seafile_rpc_client_,
+        "seafile_get_repo_property",
+        &error, 2,
+        "string", toCStr(repo_id),
+        "string", toCStr(name)
+        );
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+    *value = QString::fromUtf8(ret);
+
+    g_free(ret);
+    return 0;
+}
+
+int SeafileRpcClient::setRepoProperty(const QString &repo_id,
+                                      const QString& name,
+                                      const QString& value)
+{
+    GError *error = NULL;
+    int ret = searpc_client_call__int (
+        seafile_rpc_client_,
+        "seafile_set_repo_property",
+        &error, 3,
+        "string", toCStr(repo_id),
+        "string", toCStr(name),
+        "string", toCStr(value)
+        );
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+    return ret;
+}
+
+int SeafileRpcClient::removeSyncTokensByAccount(const QString& server_addr,
+                                                const QString& email,
+                                                QString *err)
+{
+    GError *error = NULL;
+    int ret =  searpc_client_call__int (seafile_rpc_client_,
+                                        "seafile_remove_repo_tokens_by_account",
+                                        &error, 2,
+                                        "string", toCStr(server_addr),
+                                        "string", toCStr(email));
+
+    if (ret < 0 && err) {
+        if (error) {
+            *err = QString::fromUtf8(error->message);
+            g_error_free(error);
+        } else {
+            *err = tr("Unknown error");
+        }
+    }
+
+    return ret;
+}
+
+int SeafileRpcClient::setRepoToken(const QString &repo_id,
+                                   const QString& token)
+{
+    GError *error = NULL;
+    int ret = searpc_client_call__int (
+        seafile_rpc_client_,
+        "seafile_set_repo_token",
+        &error, 2,
+        "string", toCStr(repo_id),
+        "string", toCStr(token)
+        );
+    if (error) {
+        g_error_free(error);
+        return -1;
+    }
+    return ret;
+}
+
+int SeafileRpcClient::getRepoFileStatus(const QString& repo_id,
+                                        const QString& path_in_repo,
+                                        bool isdir,
+                                        QString *status)
+{
+    GError *error = NULL;
+    char *ret = searpc_client_call__string (
+        seafile_rpc_client_,
+        "seafile_get_path_sync_status",
+        &error, 3,
+        "string", toCStr(repo_id),
+        "string", toCStr(path_in_repo),
+        "int", isdir ? 1 : 0);
+    if (error) {
+        qWarning("failed to get path status: %s\n", error->message);
+        g_error_free(error);
+        return -1;
+    }
+
+    *status = ret;
+
+    g_free (ret);
+    return 0;
+}
+
+int SeafileRpcClient::markFileLockState(const QString &repo_id,
+                                        const QString &path_in_repo,
+                                        bool lock)
+{
+    GError *error = NULL;
+    char *ret = searpc_client_call__string (
+        seafile_rpc_client_,
+        lock ? "seafile_mark_file_locked" : "seafile_mark_file_unlocked",
+        &error, 2,
+        "string", toCStr(repo_id),
+        "string", toCStr(path_in_repo));
+    if (error) {
+        qWarning("failed to mark file lock state: %s\n", error->message);
+        g_error_free(error);
+        return -1;
+    }
+
+    g_free (ret);
+    return 0;
+}
+
+int SeafileRpcClient::generateMagicAndRandomKey(int enc_version,
+                                                const QString &repo_id,
+                                                const QString &passwd,
+                                                QString *magic,
+                                                QString *random_key,
+                                                QString *salt)
+{
+    GError *error = NULL;
+    GObject *obj = searpc_client_call__object (
+        seafile_rpc_client_,
+        "seafile_generate_magic_and_random_key",
+        SEAFILE_TYPE_ENCRYPTION_INFO,
+        &error, 3,
+        "int", enc_version,
+        "string", toCStr(repo_id),
+        "string", toCStr(passwd));
+    if (error) {
+        qWarning("failed to generate magic and random_key : %s\n", error->message);
+        g_error_free(error);
+        return -1;
+    }
+
+    char *c_magic = NULL;
+    char *c_random_key = NULL;
+    char *c_salt = NULL;
+    if (enc_version == 3) {
+        g_object_get (obj,
+                    "magic", &c_magic,
+                    "random_key", &c_random_key,
+                    "salt", &c_salt,
+                    NULL);
+        *salt = QString(c_salt);
+        g_free(c_salt);
+    } else {
+        g_object_get (obj,
+            "magic", &c_magic,
+            "random_key", &c_random_key,
+            NULL);
+    }
+
+    *magic = QString(c_magic);
+    *random_key = QString(c_random_key);
+
+    g_object_unref (obj);
+    g_free (c_magic);
+    g_free (c_random_key);
+    return 0;
+}
+
+bool SeafileRpcClient::setServerProperty(const QString &url,
+                                         const QString &key,
+                                         const QString &value)
+{
+    // printf("set server config: %s %s = %s\n", toCStr(url), toCStr(key),
+    //        toCStr(value));
+    GError *error = NULL;
+    searpc_client_call__int(seafile_rpc_client_, "seafile_set_server_property",
+                            &error, 3, "string", toCStr(url), "string",
+                            toCStr(key), "string", toCStr(value));
+    if (error) {
+        qWarning("Unable to set server property %s %s", toCStr(url),
+                 toCStr(key));
+        g_error_free(error);
+        return false;
+    }
+    return true;
+}
+
+bool SeafileRpcClient::getCommitDiff(const QString& repo_id,
+                                     const QString& commit_id,
+                                     const QString& previous_commit_id,
+                                     CommitDetails *details)
+{
+    QMutexLocker locker(&threaded_rpc_mutex_);
+
+    GError *error = NULL;
+    GList *objlist = searpc_client_call__objlist(
+        seafile_threaded_rpc_client_,
+        "seafile_diff",
+        SEAFILE_TYPE_DIFF_ENTRY,
+        &error, 4,
+        "string", toCStr(repo_id),
+        "string", toCStr(commit_id),
+        "string", toCStr(previous_commit_id),
+        "int", 1);
+
+    if (error) {
+        qWarning("failed to get changes in commit %.7s of repo %.7s", toCStr(commit_id), toCStr(repo_id));
+        g_error_free(error);
+        return false;
+    }
+
+    *details = CommitDetails::fromObjList(objlist);
+
+    g_list_foreach (objlist, (GFunc)g_object_unref, NULL);
+    g_list_free (objlist);
+    return true;
+}
+
+bool SeafileRpcClient::getSyncErrors(std::vector<SyncError> *errors, int offset, int limit)
+{
+    GError *error = NULL;
+    GList *objlist = searpc_client_call__objlist(
+        seafile_rpc_client_,
+        "seafile_get_file_sync_errors",
+        SEAFILE_TYPE_FILE_SYNC_ERROR,
+        &error, 2, "int", offset, "int", limit);
+
+
+    for (GList *ptr = objlist; ptr; ptr = ptr->next) {
+        SyncError error = SyncError::fromGObject((GObject *)ptr->data);
+        errors->push_back(error);
+    }
+
+    g_list_foreach (objlist, (GFunc)g_object_unref, NULL);
+    g_list_free (objlist);
+
+    return true;
+}
+
+bool SeafileRpcClient::getSyncNotification(json_t **ret_obj)
+{
+    GError *error = NULL;
+    json_t *ret = searpc_client_call__json (
+        seafile_rpc_client_,
+        "seafile_get_sync_notification",
+        &error, 0);
+    if (error) {
+        qWarning("failed to get sync notification: %s\n",
+                 error->message ? error->message : "");
+        g_error_free(error);
+        return false;
+    }
+
+    if (!ret) {
+        // No pending notifications.
+        return false;
+    }
+
+    *ret_obj = ret;
+
+    return true;
+}
diff --git a/src/rpc/rpc-client.h b/src/rpc/rpc-client.h
new file mode 100644 (file)
index 0000000..c82fc13
--- /dev/null
@@ -0,0 +1,161 @@
+#ifndef SEAFILE_CLIENT_RPC_CLIENT_H
+#define SEAFILE_CLIENT_RPC_CLIENT_H
+
+#include <vector>
+
+#include <QObject>
+#include <QMutex>
+
+extern "C" {
+
+struct _GList;
+// Can't forward-declare type SearpcClient here because it is an anonymous typedef struct
+#include <searpc-client.h>
+
+}
+
+// Here we can't forward-declare type json_t because it is an anonymous typedef
+// struct, and unlike libsearpc we have no way to rewrite its definition to give
+// it a name.
+#include <jansson.h>
+
+class LocalRepo;
+class CloneTask;
+class SyncError;
+class CommitDetails;
+
+class SeafileRpcClient : public QObject {
+    Q_OBJECT
+
+public:
+    SeafileRpcClient();
+    ~SeafileRpcClient();
+    bool tryConnectDaemon() { return connectDaemon(false); }
+    bool connectDaemon(bool exit_on_error = true);
+    bool isConnected() const { return connected_; }
+
+    int listLocalRepos(std::vector<LocalRepo> *repos);
+    int getLocalRepo(const QString& repo_id, LocalRepo *repo);
+    int setAutoSync(const bool autoSync);
+    int downloadRepo(const QString& id,
+                     int repo_version, const QString& relayId,
+                     const QString& name, const QString& wt,
+                     const QString& token, const QString& passwd,
+                     const QString& magic, const QString& peerAddr,
+                     const QString& port, const QString& email,
+                     const QString& random_key, int enc_version,
+                     const QString& more_info,
+                     QString *error);
+
+    int cloneRepo(const QString& id,
+                  int repo_version, const QString& relayId,
+                  const QString& name, const QString& wt,
+                  const QString& token, const QString& passwd,
+                  const QString& magic, const QString& peerAddr,
+                  const QString& port, const QString& email,
+                  const QString& random_key, int enc_version,
+                  const QString& more_info,
+                  QString *error);
+
+    int seafileGetConfig(const QString& key, QString *value);
+    int seafileGetConfigInt(const QString& key, int *value);
+    int seafileSetConfig(const QString& key, const QString& value);
+    int seafileSetConfigInt(const QString& key, int value);
+
+    void getSyncStatus(LocalRepo &repo);
+    int getCloneTasks(std::vector<CloneTask> *tasks);
+    int getCloneTasksCount(int *count);
+
+    int cancelCloneTask(const QString& repo_id, QString *error);
+    int removeCloneTask(const QString& repo_id, QString *error);
+
+    int unsyncReposByAccount(const QString& server_addr, const QString& email, QString *error);
+    int removeSyncTokensByAccount(const QString& server_addr, const QString& email, QString *error);
+    int getUploadRate(int *rate);
+    int getDownloadRate(int *rate);
+
+    int getRepoTransferInfo(const QString& repo_id, int *rate, int *percent, QString* rt_state=nullptr);
+
+    void setRepoAutoSync(const QString& repo_id, bool auto_sync);
+    int unsync(const QString& repo_id);
+
+    int setUploadRateLimit(int limit);
+    int setDownloadRateLimit(int limit);
+
+    void syncRepoImmediately(const QString& repo_id);
+
+    int checkPathForClone(const QString& path, QString* err_msg);
+
+    // Helper functions
+    bool hasLocalRepo(const QString& repo_id);
+    int getServers(_GList** servers);
+
+    QString getCcnetPeerId();
+
+    int updateReposServerHost(const QString& old_host,
+                              const QString& new_host,
+                              const QString& new_server_url,
+                              QString *err);
+
+    int getRepoProperty(const QString& repo_id,
+                        const QString& name,
+                        QString *value);
+
+    int setRepoProperty(const QString& repo_id,
+                        const QString& name,
+                        const QString& value);
+
+    int setRepoToken(const QString &repo_id,
+                     const QString& token);
+
+    int getRepoFileStatus(const QString& repo_id,
+                          const QString& path_in_repo,
+                          bool isdir,
+                          QString *status);
+
+    int markFileLockState(const QString& repo_id,
+                          const QString& path_in_repo,
+                          bool lock);
+
+    int generateMagicAndRandomKey(int enc_version,
+                                  const QString& repo_id,
+                                  const QString& passwd,
+                                  QString *magic,
+                                  QString *random_key,
+                                  QString *salt);
+
+    bool setServerProperty(const QString &url,
+                           const QString &key,
+                           const QString &value);
+
+    // Read the commit diff from the daemon. Note this rpc may block for a
+    // while.
+    bool getCommitDiff(const QString& repo_id,
+                       const QString& commit_id,
+                       const QString& previous_commit_id,
+                       CommitDetails *details);
+
+    bool getSyncErrors(std::vector<SyncError> *errors, int offset=0, int limit=10);
+
+    bool getSyncNotification(json_t **ret);
+
+private:
+    Q_DISABLE_COPY(SeafileRpcClient)
+
+    void getTransferDetail(CloneTask* task);
+
+    enum Direction {
+        DOWNLOAD = 0,
+        UPLOAD
+    };
+    int setRateLimit(Direction, int limit);
+
+    bool connected_;
+
+    QMutex threaded_rpc_mutex_;
+
+    SearpcClient *seafile_rpc_client_;
+    SearpcClient *seafile_threaded_rpc_client_;
+};
+
+#endif
diff --git a/src/rpc/rpc-server.cpp b/src/rpc/rpc-server.cpp
new file mode 100644 (file)
index 0000000..a17b50e
--- /dev/null
@@ -0,0 +1,276 @@
+extern "C" {
+
+#include <searpc.h>
+#include <searpc-client.h>
+#include <searpc-server.h>
+#include <searpc-named-pipe-transport.h>
+
+#include "searpc-signature.h"
+#include "searpc-marshal.h"
+
+}
+
+#include <QCoreApplication>
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "ui/main-window.h"
+#include "open-local-helper.h"
+
+#if defined(Q_OS_WIN32)
+  #include "utils/utils-win.h"
+#endif
+
+#include "rpc-server.h"
+
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+const char *kSeafileAppletSockName = "\\\\.\\pipe\\seafile_client_";
+#else
+const char *kSeafileAppletSockName = "seafile_client.sock";
+#endif
+const char *kSeafileAppletRpcService = "seafile-client-rpcserver";
+
+QString getAppletRpcPipePath()
+{
+#if defined(Q_OS_WIN32)
+    return utils::win::getLocalPipeName(kSeafileAppletSockName).c_str();
+#else
+    seafApplet->configurator()->checkInit();
+    return QDir(seafApplet->configurator()->seafileDir()).filePath(kSeafileAppletSockName);
+#endif
+}
+
+char *
+handle_ping_command (GError **error)
+{
+    return strdup("pong");
+}
+
+int
+handle_activate_command (GError **error)
+{
+    qWarning("[rpc server] Got an activate command");
+    RpcServerProxy::instance()->proxyActivateCommand();
+    return 0;
+}
+
+int
+handle_exit_command (GError **error)
+{
+    qWarning("[rpc server] Got a quit command. Quit now.");
+    RpcServerProxy::instance()->proxyExitCommand();
+    return 0;
+}
+
+int
+handle_open_seafile_url_command (const char *url, GError **error)
+{
+    qWarning("[rpc server] opening seafile url %s", url);
+    RpcServerProxy::instance()->proxyOpenSeafileUrlCommand(QUrl::fromEncoded(url));
+    return 0;
+}
+
+void register_rpc_service ()
+{
+    searpc_server_init ((RegisterMarshalFunc)register_marshals);
+
+    searpc_create_service (kSeafileAppletRpcService);
+
+    searpc_server_register_function (kSeafileAppletRpcService,
+                                     (void *)handle_ping_command,
+                                     "ping",
+                                     searpc_signature_string__void());
+
+    searpc_server_register_function (kSeafileAppletRpcService,
+                                     (void *)handle_activate_command,
+                                     "activate",
+                                     searpc_signature_int__void());
+
+    searpc_server_register_function (kSeafileAppletRpcService,
+                                     (void *)handle_exit_command,
+                                     "exit",
+                                     searpc_signature_int__void());
+
+    searpc_server_register_function (kSeafileAppletRpcService,
+                                     (void *)handle_open_seafile_url_command,
+                                     "open_seafile_url",
+                                     searpc_signature_int__string());
+}
+
+
+SearpcClient *createSearpcClientWithPipeTransport(const char *rpc_service)
+{
+    SearpcNamedPipeClient *pipe_client;
+    pipe_client = searpc_create_named_pipe_client(toCStr(getAppletRpcPipePath()));
+    int ret = searpc_named_pipe_client_connect(pipe_client);
+    SearpcClient *c = searpc_client_with_named_pipe_transport(pipe_client, rpc_service);
+    if (ret < 0) {
+        searpc_free_client_with_pipe_transport(c);
+        return nullptr;
+    }
+    return c;
+}
+
+class AppletRpcClient : public SeafileAppletRpcServer::Client {
+public:
+    bool connect() {
+        seafile_rpc_client_ = createSearpcClientWithPipeTransport(kSeafileAppletRpcService);
+        if (!seafile_rpc_client_) {
+            return false;
+        }
+        return true;
+    }
+    bool sendPingCommand(QString* resp) {
+        GError *error = NULL;
+        char *ret = searpc_client_call__string (
+            seafile_rpc_client_,
+            "ping",
+            &error, 0);
+        if (error) {
+            g_error_free(error);
+            return false;
+        }
+        if (!ret) {
+            return false;
+        }
+        *resp = ret;
+        return true;
+    }
+
+    bool sendActivateCommand() {
+        GError *error = NULL;
+        int ret = searpc_client_call__int (
+            seafile_rpc_client_,
+            "activate",
+            &error, 0);
+        if (error) {
+            g_error_free(error);
+            return false;
+        }
+        if (ret != 0) {
+            return false;
+        }
+        return true;
+    }
+    bool sendExitCommand() {
+        GError *error = NULL;
+        int ret = searpc_client_call__int (
+            seafile_rpc_client_,
+            "exit",
+            &error, 0);
+        if (error) {
+            g_error_free(error);
+            return false;
+        }
+        if (ret != 0) {
+            return false;
+        }
+        return true;
+    }
+
+    bool sendOpenSeafileUrlCommand(const QUrl& url) {
+        GError *error = NULL;
+        int ret = searpc_client_call__int (
+            seafile_rpc_client_,
+            "open_seafile_url",
+            &error, 1, "string", url.toEncoded().data());
+        if (error) {
+            g_error_free(error);
+            return false;
+        }
+        if (ret != 0) {
+            return false;
+        }
+        return true;
+    }
+private:
+    SearpcClient *seafile_rpc_client_;
+
+};
+
+} // namespace
+
+struct SeafileAppletRpcServerPriv {
+    SearpcNamedPipeServer *pipe_server;
+};
+
+
+SINGLETON_IMPL(SeafileAppletRpcServer)
+
+SeafileAppletRpcServer::SeafileAppletRpcServer()
+: priv_(new SeafileAppletRpcServerPriv)
+{
+    priv_->pipe_server = searpc_create_named_pipe_server(toCStr(getAppletRpcPipePath()));
+
+    RpcServerProxy *proxy = RpcServerProxy::instance();
+    connect(
+        proxy, SIGNAL(activateCommand()), this, SLOT(handleActivateCommand()));
+    connect(proxy, SIGNAL(exitCommand()), this, SLOT(handleExitCommand()));
+    connect(proxy,
+            SIGNAL(openSeafileUrlCommand(const QUrl &)),
+            this,
+            SLOT(handleOpenSeafileUrlCommand(const QUrl &)));
+}
+
+SeafileAppletRpcServer::~SeafileAppletRpcServer()
+{
+}
+
+void SeafileAppletRpcServer::start()
+{
+    register_rpc_service();
+    qWarning("starting applet rpc service");
+    if (searpc_named_pipe_server_start(priv_->pipe_server) < 0) {
+        qWarning("failed to start rpc service");
+        seafApplet->errorAndExit("failed to initialize");
+    } else {
+        qWarning("applet rpc service started");
+    }
+}
+
+SeafileAppletRpcServer::Client* SeafileAppletRpcServer::getClient()
+{
+    return new AppletRpcClient();
+}
+
+void SeafileAppletRpcServer::handleActivateCommand()
+{
+    seafApplet->mainWindow()->showWindow();
+}
+
+void SeafileAppletRpcServer::handleExitCommand()
+{
+    qWarning("[Message Listener] Got a quit command. Quit now.");
+    QCoreApplication::exit(0);
+}
+
+void SeafileAppletRpcServer::handleOpenSeafileUrlCommand(const QUrl& url)
+{
+    OpenLocalHelper::instance()->openLocalFile(url);
+}
+
+
+SINGLETON_IMPL(RpcServerProxy)
+
+RpcServerProxy::RpcServerProxy()
+{
+}
+
+void RpcServerProxy::proxyActivateCommand()
+{
+    emit activateCommand();
+}
+
+void RpcServerProxy::proxyExitCommand()
+{
+    emit exitCommand();
+}
+
+void RpcServerProxy::proxyOpenSeafileUrlCommand(const QUrl& url)
+{
+    emit openSeafileUrlCommand(url);
+}
diff --git a/src/rpc/rpc-server.h b/src/rpc/rpc-server.h
new file mode 100644 (file)
index 0000000..118100c
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef SEAFILE_CLIENT_RPC_SERVER_H
+#define SEAFILE_CLIENT_RPC_SERVER_H
+
+#include <QObject>
+
+#include "utils/singleton.h"
+
+struct SeafileAppletRpcServerPriv;
+
+// This is the rpc server componet to accept commands like --stop,
+// --remove-user-data, and open seafile:// protocol url, etc.
+class SeafileAppletRpcServer : public QObject {
+    SINGLETON_DEFINE(SeafileAppletRpcServer)
+    Q_OBJECT
+public:
+    SeafileAppletRpcServer();
+    ~SeafileAppletRpcServer();
+
+    void start();
+
+    class Client {
+    public:
+        virtual bool connect() = 0;
+        virtual bool sendPingCommand(QString* resp) = 0;
+        virtual bool sendActivateCommand() = 0;
+        virtual bool sendExitCommand() = 0;
+        virtual bool sendOpenSeafileUrlCommand(const QUrl& url) = 0;
+    };
+
+    static Client* getClient();
+
+private slots:
+    void handleActivateCommand();
+    void handleExitCommand();
+    void handleOpenSeafileUrlCommand(const QUrl& url);
+
+private:
+    SeafileAppletRpcServerPriv *priv_;
+};
+
+// Helper object to proxy the rpc commands from the rpc server thread
+// to the main thread (using signals/slots). We need this because,
+// e.g. we can't call QCoreApplication::exit() from non-main thread.
+class RpcServerProxy : public QObject {
+    SINGLETON_DEFINE(RpcServerProxy)
+    Q_OBJECT
+
+public:
+    RpcServerProxy();
+
+    void proxyExitCommand();
+    void proxyActivateCommand();
+    void proxyOpenSeafileUrlCommand(const QUrl&);
+
+signals:
+    void exitCommand();
+    void activateCommand();
+    void openSeafileUrlCommand(const QUrl&);
+};
+
+#endif
diff --git a/src/rpc/rpc_table.py b/src/rpc/rpc_table.py
new file mode 100644 (file)
index 0000000..a30da4e
--- /dev/null
@@ -0,0 +1,10 @@
+"""
+Define RPC functions needed to generate
+"""
+
+# [ <ret-type>, [<arg_types>] ]
+func_table = [
+    [ "int", [] ],
+    [ "int", ["string"] ],
+    [ "string", [] ],
+]
diff --git a/src/rpc/searpc-marshal.h b/src/rpc/searpc-marshal.h
new file mode 100644 (file)
index 0000000..81bc69a
--- /dev/null
@@ -0,0 +1,58 @@
+
+static char *
+marshal_int__void (void *func, json_t *param_array, gsize *ret_len)
+{
+    GError *error = NULL;
+
+    int ret = ((int (*)(GError **))func) (&error);
+
+    json_t *object = json_object ();
+    searpc_set_int_to_ret_object (object, ret);
+    return searpc_marshal_set_ret_common (object, ret_len, error);
+}
+
+
+static char *
+marshal_int__string (void *func, json_t *param_array, gsize *ret_len)
+{
+    GError *error = NULL;
+    const char* param1 = json_array_get_string_or_null_element (param_array, 1);
+
+    int ret = ((int (*)(const char*, GError **))func) (param1, &error);
+
+    json_t *object = json_object ();
+    searpc_set_int_to_ret_object (object, ret);
+    return searpc_marshal_set_ret_common (object, ret_len, error);
+}
+
+
+static char *
+marshal_string__void (void *func, json_t *param_array, gsize *ret_len)
+{
+    GError *error = NULL;
+
+    char* ret = ((char* (*)(GError **))func) (&error);
+
+    json_t *object = json_object ();
+    searpc_set_string_to_ret_object (object, ret);
+    return searpc_marshal_set_ret_common (object, ret_len, error);
+}
+
+static void register_marshals()
+{
+
+    {
+        searpc_server_register_marshal (searpc_signature_int__void(), marshal_int__void);
+    }
+
+
+    {
+        searpc_server_register_marshal (searpc_signature_int__string(), marshal_int__string);
+    }
+
+
+    {
+        searpc_server_register_marshal (searpc_signature_string__void(), marshal_string__void);
+    }
+
+}
diff --git a/src/rpc/searpc-signature.h b/src/rpc/searpc-signature.h
new file mode 100644 (file)
index 0000000..7df7cc1
--- /dev/null
@@ -0,0 +1,21 @@
+
+inline static gchar *
+searpc_signature_int__void()
+{
+    return searpc_compute_signature ("int", 0);
+}
+
+
+inline static gchar *
+searpc_signature_int__string()
+{
+    return searpc_compute_signature ("int", 1, "string");
+}
+
+
+inline static gchar *
+searpc_signature_string__void()
+{
+    return searpc_compute_signature ("string", 0);
+}
+
diff --git a/src/rpc/sync-error.cpp b/src/rpc/sync-error.cpp
new file mode 100644 (file)
index 0000000..2efd267
--- /dev/null
@@ -0,0 +1,94 @@
+#include <QObject>
+#include <QStringList>
+#include <glib-object.h>
+
+#include "utils/utils.h"
+#include "sync-error.h"
+
+SyncError SyncError::fromGObject(GObject *obj)
+{
+    SyncError error;
+
+    char *repo_id = NULL;
+    char *repo_name = NULL;
+    char *path = NULL;
+    int error_id = 0;
+    qint64 timestamp = 0;
+
+    g_object_get (obj,
+                  "repo_id", &repo_id,
+                  "repo_name", &repo_name,
+                  "path", &path,
+                  "err_id", &error_id,
+                  "timestamp", &timestamp,
+                  NULL);
+
+    error.repo_id = repo_id;
+    error.repo_name = QString::fromUtf8(repo_name);
+    error.path = QString::fromUtf8(path);
+
+    error.error_id = error_id;
+    error.timestamp = timestamp;
+
+    g_free (repo_id);
+    g_free (repo_name);
+    g_free (path);
+
+    error.translateErrorStr();
+
+    return error;
+}
+
+// Copied from seafile/daemon/repo-mgr.h
+#define SYNC_ERROR_ID_FILE_LOCKED_BY_APP 0
+#define SYNC_ERROR_ID_FOLDER_LOCKED_BY_APP 1
+#define SYNC_ERROR_ID_FILE_LOCKED 2
+#define SYNC_ERROR_ID_INVALID_PATH 3
+#define SYNC_ERROR_ID_INDEX_ERROR 4
+#define SYNC_ERROR_ID_PATH_END_SPACE_PERIOD 5
+#define SYNC_ERROR_ID_PATH_INVALID_CHARACTER 6
+#define SYNC_ERROR_ID_FOLDER_PERM_DENIED 7
+#define SYNC_ERROR_ID_PERM_NOT_SYNCABLE 8
+#define SYNC_ERROR_ID_UPDATE_TO_READ_ONLY_REPO 9
+
+void SyncError::translateErrorStr()
+{
+    readable_time_stamp = translateCommitTime(timestamp);
+
+    switch (error_id) {
+    case SYNC_ERROR_ID_FILE_LOCKED_BY_APP:
+        error_str = QObject::tr("File is locked by another application");
+        break;
+    case SYNC_ERROR_ID_FOLDER_LOCKED_BY_APP:
+        error_str = QObject::tr("Folder is locked by another application");
+        break;
+    case SYNC_ERROR_ID_FILE_LOCKED:
+        error_str = QObject::tr("File is locked by another user");
+        break;
+    case SYNC_ERROR_ID_INVALID_PATH:
+        error_str = QObject::tr("Path is invalid");
+        break;
+    case SYNC_ERROR_ID_INDEX_ERROR:
+        error_str = QObject::tr("Error when indexing");
+        break;
+    case SYNC_ERROR_ID_PATH_END_SPACE_PERIOD:
+        error_str = QObject::tr("Path ends with space or period character");
+        break;
+    case SYNC_ERROR_ID_PATH_INVALID_CHARACTER:
+        error_str = QObject::tr("Path contains invalid characters like '|' or ':'");
+        break;
+    case SYNC_ERROR_ID_FOLDER_PERM_DENIED:
+        error_str = QObject::tr("Update to file denied by folder permission setting");
+        break;
+    case SYNC_ERROR_ID_PERM_NOT_SYNCABLE:
+        error_str = QObject::tr("No permission to sync this folder");
+        break;
+    case SYNC_ERROR_ID_UPDATE_TO_READ_ONLY_REPO:
+        error_str = QObject::tr("Updates in read-only library will not be uploaded");
+        break;
+    default:
+        // unreachable
+        qWarning("unknown sync error id %d", error_id);
+        error_str = "";
+    }
+}
diff --git a/src/rpc/sync-error.h b/src/rpc/sync-error.h
new file mode 100644 (file)
index 0000000..2e75e97
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef SEAFILE_CLIENT_RPC_SYNC_ERROR_H
+#define SEAFILE_CLIENT_RPC_SYNC_ERROR_H
+
+#include <QString>
+#include <QMetaType>
+
+struct _GObject;
+
+class SyncError {
+public:
+    QString repo_id;
+    QString repo_name;
+    QString path;
+    qint64 timestamp;
+    int error_id;
+
+    // Generated fields.
+    QString readable_time_stamp;
+    QString error_str;
+
+    static SyncError fromGObject(_GObject *obj);
+
+    void translateErrorStr();
+
+    bool operator==(const SyncError& rhs) const {
+        return repo_id == rhs.repo_id
+            && repo_name == rhs.repo_name
+            && path == rhs.path
+            && error_id == rhs.error_id
+            && timestamp == rhs.timestamp;
+    }
+
+    bool operator!=(const SyncError& rhs) const {
+        return !(*this == rhs);
+    }
+};
+
+#endif // SEAFILE_CLIENT_RPC_SYNC_ERROR_H
diff --git a/src/rpc/update_rpc_sigs.sh b/src/rpc/update_rpc_sigs.sh
new file mode 100755 (executable)
index 0000000..0b288fc
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -e
+
+# this seems to cover the bases on OSX, and someone will
+# have to tell me about the others.
+get_script_path () {
+  local path="$1"
+  [[ -L "$path" ]] || { echo "$path" ; return; }
+
+  local target="$(readlink "$path")"
+  if [[ "${target:0:1}" == "/" ]]; then
+    echo "$target"
+  else
+    echo "${path%/*}/$target"
+  fi
+}
+
+declare -r script_path="$(get_script_path "$BASH_SOURCE")"
+declare -r script_dir="${script_path%/*}"
+
+cd $script_dir
+searpc-codegen.py rpc_table.py
diff --git a/src/seafile-applet.cpp b/src/seafile-applet.cpp
new file mode 100644 (file)
index 0000000..018e5ba
--- /dev/null
@@ -0,0 +1,791 @@
+#include <QtGlobal>
+
+#include <QtWidgets>
+#include <QApplication>
+#include <QDesktopServices>
+#include <QFile>
+#include <QTextStream>
+#include <QDir>
+#include <QCoreApplication>
+#include <QMessageBox>
+#include <QTimer>
+#include <QHostInfo>
+
+#include <errno.h>
+#include <glib.h>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/log.h"
+#include "account-mgr.h"
+#include "configurator.h"
+#include "daemon-mgr.h"
+#include "message-poller.h"
+#include "settings-mgr.h"
+#include "certs-mgr.h"
+#include "rpc/rpc-client.h"
+#include "ui/main-window.h"
+#include "ui/tray-icon.h"
+#include "ui/settings-dialog.h"
+#include "ui/init-vdrive-dialog.h"
+#include "ui/login-dialog.h"
+#include "open-local-helper.h"
+#include "avatar-service.h"
+#include "filebrowser/thumbnail-service.h"
+#include "filebrowser/data-cache.h"
+#include "filebrowser/auto-update-mgr.h"
+#include "filebrowser/data-mgr.h"
+#include "rpc/local-repo.h"
+#include "rpc/rpc-server.h"
+#include "network-mgr.h"
+#include "server-status-service.h"
+#include "account-info-service.h"
+#include "customization-service.h"
+
+#if defined(Q_OS_WIN32)
+    #include "ext-handler.h"
+    #include "utils/registry.h"
+#elif defined(HAVE_FINDER_SYNC_SUPPORT)
+    #include "finder-sync/finder-sync-listener.h"
+#endif
+
+#ifdef HAVE_SPARKLE_SUPPORT
+#include "auto-update-service.h"
+#endif
+
+
+#if defined(Q_OS_MAC)
+#include "utils/utils-mac.h"
+#endif
+
+#include "seafile-applet.h"
+
+namespace {
+enum DEBUG_LEVEL {
+  DEBUG = 0,
+  WARNING
+};
+
+// -DQT_NO_DEBUG is used with cmake and qmake if it is a release build
+// if it is debug build, use DEBUG level as default
+#if !defined(QT_NO_DEBUG) || !defined(NDEBUG)
+DEBUG_LEVEL seafile_client_debug_level = DEBUG;
+#else
+// if it is release build, use WARNING level as default
+DEBUG_LEVEL seafile_client_debug_level = WARNING;
+#endif
+
+void myLogHandlerDebug(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+    QByteArray localMsg = msg.toLocal8Bit();
+    switch (type) {
+// Note: By default, this information (QMessageLogContext) is recorded only in debug builds.
+// You can overwrite this explicitly by defining QT_MESSAGELOGCONTEXT or QT_NO_MESSAGELOGCONTEXT.
+// from http://doc.qt.io/qt-5/qmessagelogcontext.html
+#ifdef QT_MESSAGELOGCONTEXT
+    case QtDebugMsg:
+        g_debug("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+        break;
+    case QtWarningMsg:
+        g_warning("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+        break;
+    case QtCriticalMsg:
+        g_critical("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+        break;
+    case QtFatalMsg:
+        g_critical("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+        abort();
+#else // QT_MESSAGELOGCONTEXT
+    case QtDebugMsg:
+        g_debug("%s\n", localMsg.constData());
+        break;
+    case QtWarningMsg:
+        g_warning("%s\n", localMsg.constData());
+        break;
+    case QtCriticalMsg:
+        g_critical("%s\n", localMsg.constData());
+        break;
+    case QtFatalMsg:
+        g_critical("%s\n", localMsg.constData());
+        abort();
+#endif // QT_MESSAGELOGCONTEXT
+    default:
+        break;
+    }
+}
+void myLogHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+    QByteArray localMsg = msg.toLocal8Bit();
+    switch (type) {
+#ifdef QT_MESSAGELOGCONTEXT
+    case QtWarningMsg:
+        g_warning("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+        break;
+    case QtCriticalMsg:
+        g_critical("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+        break;
+    case QtFatalMsg:
+        g_critical("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+        abort();
+#else // QT_MESSAGELOGCONTEXT
+    case QtWarningMsg:
+        g_warning("%s\n", localMsg.constData());
+        break;
+    case QtCriticalMsg:
+        g_critical("%s\n", localMsg.constData());
+        break;
+    case QtFatalMsg:
+        g_critical("%s\n", localMsg.constData());
+        abort();
+#endif // QT_MESSAGELOGCONTEXT
+    default:
+        break;
+    }
+}
+
+#ifdef Q_OS_MAC
+void writeCABundleForCurl()
+{
+    QString ca_bundle_path = QDir(seafApplet->configurator()->seafileDir()).filePath("ca-bundle.pem");
+    QFile bundle(ca_bundle_path);
+    if (bundle.exists()) {
+        bundle.remove();
+    }
+    bundle.open(QIODevice::WriteOnly);
+    const std::vector<QByteArray> certs = utils::mac::getSystemCaCertificates();
+    for (size_t i = 0; i < certs.size(); i++) {
+        QList<QSslCertificate> list = QSslCertificate::fromData(certs[i], QSsl::Der);
+        foreach (const QSslCertificate& cert, list) {
+            bundle.write(cert.toPem());
+        }
+    }
+}
+#endif
+
+
+const char *const kPreconfigureUsername = "PreconfigureUsername";
+const char *const kPreconfigureUserToken = "PreconfigureUserToken";
+const char *const kPreconfigureServerAddr = "PreconfigureServerAddr";
+const char *const kPreconfigureComputerName = "PreconfigureComputerName";
+const char* const kHideConfigurationWizard = "HideConfigurationWizard";
+#if defined(Q_OS_WIN32)
+const char *const kSeafileConfigureFileName = "seafile.ini";
+const char *const kSeafileConfigurePath = "SOFTWARE\\Seafile";
+const int kIntervalBeforeShowInitVirtualDialog = 3000;
+#else
+const char *const kSeafileConfigureFileName = ".seafilerc";
+#endif
+const char *const kSeafilePreconfigureGroupName = "preconfigure";
+
+const int kIntervalForUpdateRepoProperty = 1000;
+
+const char *kRepoServerUrlProperty = "server-url";
+const char *kRepoRelayAddrProperty = "relay-address";
+
+} // namespace
+
+
+SeafileApplet *seafApplet;
+
+SeafileApplet::SeafileApplet()
+    : configurator_(new Configurator),
+      account_mgr_(new AccountManager),
+      daemon_mgr_(new DaemonManager),
+      main_win_(NULL),
+      rpc_client_(new SeafileRpcClient),
+      message_poller_(new MessagePoller),
+      settings_dialog_(new SettingsDialog),
+      settings_mgr_(new SettingsManager),
+      certs_mgr_(new CertsManager),
+      data_mgr_(new DataManager),
+      started_(false),
+      in_exit_(false),
+      is_pro_(false),
+      about_to_quit_(false)
+{
+    tray_icon_ = new SeafileTrayIcon(this);
+    connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(onAboutToQuit()));
+}
+
+SeafileApplet::~SeafileApplet()
+{
+    NetworkStatusDetector::instance()->stop();
+
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+    finderSyncListenerStop();
+#endif
+    delete tray_icon_;
+    delete certs_mgr_;
+    delete settings_dialog_;
+    delete message_poller_;
+    delete rpc_client_;
+    delete account_mgr_;
+    // seafile-applet exit will inform seaf-daemon to clean sync token,
+    // so the class object deamon_mgr daemon_mgr_ dealloc after account_mgr_.
+
+    delete daemon_mgr_;
+    delete configurator_;
+    delete data_mgr_;
+    if (main_win_)
+        delete main_win_;
+#if defined(Q_OS_WIN32)
+    SeafileExtensionHandler::instance()->stop();
+
+#ifdef HAVE_SPARKLE_SUPPORT
+    AutoUpdateService::instance()->stop();
+#endif
+
+#endif
+}
+
+void SeafileApplet::start()
+{
+    refreshQss();
+
+    configurator_->checkInit();
+
+    initLog();
+
+    qDebug("client id is %s", toCStr(getUniqueClientId()));
+    account_mgr_->start();
+
+    certs_mgr_->start();
+
+    data_mgr_->start();
+
+#if defined(Q_OS_WIN32)
+    QString crash_rpt_path = QDir(configurator_->ccnetDir()).filePath("logs/seafile-crash-report.txt");
+    if (!g_setenv ("CRASH_RPT_PATH", toCStr(crash_rpt_path), FALSE))
+        qWarning("Failed to set CRASH_RPT_PATH env variable.\n");
+#endif
+
+#if defined(Q_OS_MAC)
+    writeCABundleForCurl();
+#endif
+
+    // Load system proxy information. This must be done before we start
+    // seaf-daemon.
+    settings_mgr_->writeSystemProxyInfo(
+        account_mgr_->currentAccount().serverUrl,
+        QDir(configurator_->seafileDir()).filePath("system-proxy.txt"));
+
+    FileCache::instance()->start();
+
+    //
+    // start daemons
+    //
+    daemon_mgr_->startSeafileDaemon();
+
+    connect(daemon_mgr_, SIGNAL(daemonStarted()),
+            this, SLOT(onDaemonStarted()));
+    connect(daemon_mgr_, SIGNAL(daemonRestarted()),
+            this, SLOT(onDaemonRestarted()));
+}
+
+void SeafileApplet::onDaemonStarted()
+{
+    //
+    // start daemon-related services
+    //
+    rpc_client_->connectDaemon();
+
+    // Sleep 500 millseconds to wait seafile registering services
+
+    msleep(500);
+
+    //
+    // load proxy settings (important)
+    //
+    settings_mgr_->loadSettings();
+
+    //
+    // start network-related services
+    //
+    NetworkStatusDetector::instance()->start();
+    AutoUpdateManager::instance()->start();
+
+    AvatarService::instance()->start();
+    ThumbnailService::instance()->start();
+
+    ServerStatusService::instance()->start();
+    CustomizationService::instance()->start();
+    AccountInfoService::instance()->start();
+    SeafileAppletRpcServer::instance()->start();
+
+    account_mgr_->updateServerInfo();
+
+    //
+    // start ui part
+    //
+    main_win_ = new MainWindow;
+
+#if defined(Q_OS_MAC)
+    seafApplet->settingsManager()->setHideDockIcon(seafApplet->settingsManager()->hideDockIcon());
+#endif
+
+#ifdef XCODE_APP
+    if (configurator_->firstUse()) {
+        settings_mgr_->setAutoStart(true);
+    }
+#endif
+
+    if (configurator_->firstUse() || account_mgr_->accounts().size() == 0) {
+        do {
+            QString username = readPreconfigureExpandedString(kPreconfigureUsername);
+            QString token = readPreconfigureExpandedString(kPreconfigureUserToken);
+            QString url = readPreconfigureExpandedString(kPreconfigureServerAddr);
+            QString computer_name = readPreconfigureExpandedString(kPreconfigureComputerName, settingsManager()->getComputerName());
+            if (!computer_name.isEmpty())
+                settingsManager()->setComputerName(computer_name);
+            if (!username.isEmpty() && !token.isEmpty() && !url.isEmpty()) {
+                Account account(url, username, token);
+                if (account_mgr_->saveAccount(account) < 0) {
+                    errorAndExit(tr("failed to add default account"));
+                }
+                break;
+            }
+
+            if (readPreconfigureEntry(kHideConfigurationWizard).toInt())
+                break;
+            LoginDialog login_dialog;
+            login_dialog.exec();
+        } while (0);
+    } else if (!account_mgr_->accounts().empty()) {
+        const Account &account = account_mgr_->accounts()[0];
+        account_mgr_->removeNonautoLoginSyncTokens();
+        account_mgr_->validateAndUseAccount(account);
+    }
+
+    started_ = true;
+
+    if (configurator_->firstUse() || !settings_mgr_->hideMainWindowWhenStarted()) {
+        main_win_->showWindow();
+    }
+
+    tray_icon_->start();
+    tray_icon_->setState(SeafileTrayIcon::STATE_DAEMON_UP);
+    message_poller_->start();
+
+
+#if defined(Q_OS_WIN32)
+    QTimer::singleShot(kIntervalBeforeShowInitVirtualDialog, this, SLOT(checkInitVDrive()));
+    configurator_->installCustomUrlHandler();
+#endif
+
+    QString value;
+    if (seafApplet->rpcClient()->seafileGetConfig("client_name", &value) < 0 || value.isEmpty()) {
+        // We do this because clients before 6.0 don't set the "client_name" option.
+        seafApplet->rpcClient()->seafileSetConfig(
+        "client_name", settings_mgr_->getComputerName());
+    }
+
+    // Set the device id to the daemon so it can use it when generating commits.
+    // The "client_name" is not set here, but updated each time we call
+    // switch_account rpc.
+    if (rpc_client_->seafileGetConfig("client_id", &value) < 0 ||
+        value.isEmpty() || value != getUniqueClientId()) {
+        rpc_client_->seafileSetConfig("client_id", getUniqueClientId());
+    }
+
+    QTimer::singleShot(kIntervalForUpdateRepoProperty,
+                       this, SLOT(updateReposPropertyForHttpSync()));
+
+    //
+    // start finder/explorer extension handler
+    //
+#if defined(Q_OS_WIN32)
+    SeafileExtensionHandler::instance()->start();
+#elif defined(HAVE_FINDER_SYNC_SUPPORT)
+    finderSyncListenerStart();
+#endif
+
+#ifdef HAVE_SPARKLE_SUPPORT
+    if (AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
+        AutoUpdateService::instance()->start();
+    }
+#endif
+}
+
+void SeafileApplet::checkInitVDrive()
+{
+    if (configurator_->firstUse() && account_mgr_->hasAccount()) {
+        const Account account = account_mgr_->currentAccount();
+        InitVirtualDriveDialog *dialog = new InitVirtualDriveDialog(account);
+        // Move the dialog to the left of the main window
+        int x = main_win_->pos().x() - dialog->rect().width() - 30;
+        int y = (QApplication::desktop()->screenGeometry().center() - dialog->rect().center()).y();
+        dialog->move(qMax(0, x), y);
+        dialog->show();
+        dialog->raise();
+        dialog->activateWindow();
+    }
+}
+
+void SeafileApplet::onAboutToQuit()
+{
+    about_to_quit_ = true;
+    tray_icon_->hide();
+    if (main_win_) {
+        main_win_->writeSettings();
+    }
+}
+// stop the main event loop and return to the main function
+void SeafileApplet::errorAndExit(const QString& error)
+{
+    if (in_exit_ || QCoreApplication::closingDown()) {
+        return;
+    }
+
+    in_exit_ = true;
+
+    warningBox(error);
+    // stop eventloop before exit and return to the main function
+    QCoreApplication::exit(1);
+}
+
+void SeafileApplet::restartApp()
+{
+    if (in_exit_ || QCoreApplication::closingDown()) {
+        return;
+    }
+
+    in_exit_ = true;
+
+    QStringList args = QApplication::arguments();
+
+    args.removeFirst();
+
+    // append delay argument
+    bool found = false;
+    Q_FOREACH(const QString& arg, args)
+    {
+        if (arg == "--delay" || arg == "-D") {
+            found = true;
+            break;
+        }
+    }
+
+    if (!found)
+        args.push_back("--delay");
+
+    QProcess::startDetached(QApplication::applicationFilePath(), args);
+    QCoreApplication::quit();
+}
+
+void SeafileApplet::initLog()
+{
+    if (applet_log_init(toCStr(configurator_->ccnetDir())) < 0) {
+        errorAndExit(tr("Failed to initialize log: %s").arg(g_strerror(errno)));
+    } else {
+        // give a change to override DEBUG_LEVEL by environment
+        QString debug_level = qgetenv("SEAFILE_CLIENT_DEBUG");
+        if (!debug_level.isEmpty() && debug_level != "false" &&
+            debug_level != "0")
+            seafile_client_debug_level = DEBUG;
+
+        if (seafile_client_debug_level == DEBUG)
+            qInstallMessageHandler(myLogHandlerDebug);
+        else
+            qInstallMessageHandler(myLogHandler);
+    }
+}
+
+bool SeafileApplet::loadQss(const QString& path)
+{
+    QFile file(path);
+    if (!QFileInfo(file).exists()) {
+        return false;
+    }
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        return false;
+    }
+
+    QTextStream input(&file);
+    style_ += "\n";
+    style_ += input.readAll();
+    qApp->setStyleSheet(style_);
+
+    return true;
+}
+
+void SeafileApplet::refreshQss()
+{
+    style_.clear();
+    loadQss("qt.css") || loadQss(":/qt.css");
+
+#if defined(Q_OS_WIN32)
+    loadQss("qt-win.css") || loadQss(":/qt-win.css");
+#elif defined(Q_OS_LINUX)
+    loadQss("qt-linux.css") || loadQss(":/qt-linux.css");
+#else
+    loadQss("qt-mac.css") || loadQss(":/qt-mac.css");
+#endif
+}
+
+void SeafileApplet::warningBox(const QString& msg, QWidget *parent)
+{
+    QMessageBox box(parent ? parent : main_win_);
+    box.setText(msg);
+    box.setWindowTitle(getBrand());
+    box.setIcon(QMessageBox::Warning);
+    box.addButton(tr("OK"), QMessageBox::YesRole);
+    box.exec();
+
+    if (!parent && main_win_) {
+        main_win_->showWindow();
+    }
+    qWarning("%s", msg.toUtf8().data());
+}
+
+void SeafileApplet::messageBox(const QString& msg, QWidget *parent)
+{
+    QMessageBox box(parent ? parent : main_win_);
+    box.setText(msg);
+    box.setWindowTitle(getBrand());
+    box.setIcon(QMessageBox::Information);
+    box.addButton(tr("OK"), QMessageBox::YesRole);
+    box.exec();
+    qDebug("%s", msg.toUtf8().data());
+}
+
+bool SeafileApplet::yesOrNoBox(const QString& msg, QWidget *parent, bool default_val)
+{
+    QMessageBox box(parent ? parent : main_win_);
+    box.setText(msg);
+    box.setWindowTitle(getBrand());
+    box.setIcon(QMessageBox::Question);
+    QPushButton *yes_btn = box.addButton(tr("Yes"), QMessageBox::YesRole);
+    QPushButton *no_btn = box.addButton(tr("No"), QMessageBox::NoRole);
+    box.setDefaultButton(default_val ? yes_btn: no_btn);
+    box.exec();
+
+    return box.clickedButton() == yes_btn;
+}
+
+bool SeafileApplet::yesOrCancelBox(const QString& msg, QWidget *parent, bool default_yes)
+{
+    QMessageBox box(parent ? parent : main_win_);
+    box.setText(msg);
+    box.setWindowTitle(getBrand());
+    box.setIcon(QMessageBox::Question);
+    QPushButton *yes_btn = box.addButton(tr("Yes"), QMessageBox::YesRole);
+    QPushButton *cancel_btn = box.addButton(tr("Cancel"), QMessageBox::RejectRole);
+    box.setDefaultButton(default_yes ? yes_btn: cancel_btn);
+    box.exec();
+
+    return box.clickedButton() == yes_btn;
+}
+
+
+QMessageBox::StandardButton
+SeafileApplet::yesNoCancelBox(const QString& msg, QWidget *parent, QMessageBox::StandardButton default_btn)
+{
+    QMessageBox box(parent ? parent : main_win_);
+    box.setText(msg);
+    box.setWindowTitle(getBrand());
+    box.setIcon(QMessageBox::Question);
+    QPushButton *yes_btn = box.addButton(tr("Yes"), QMessageBox::YesRole);
+    QPushButton *no_btn = box.addButton(tr("No"), QMessageBox::NoRole);
+    box.addButton(tr("Cancel"), QMessageBox::RejectRole);
+    box.setDefaultButton(default_btn);
+    box.exec();
+
+    QAbstractButton *btn = box.clickedButton();
+    if (btn == yes_btn) {
+        return QMessageBox::Yes;
+    } else if (btn == no_btn) {
+        return QMessageBox::No;
+    }
+
+    return QMessageBox::Cancel;
+}
+
+bool SeafileApplet::detailedYesOrNoBox(const QString& msg, const QString& detailed_text, QWidget *parent, bool default_val)
+{
+    QMessageBox msgBox(QMessageBox::Question,
+                       getBrand(),
+                       msg,
+                       QMessageBox::Yes | QMessageBox::No,
+                       parent != 0 ? parent : main_win_);
+    msgBox.setDetailedText(detailed_text);
+    msgBox.setButtonText(QMessageBox::Yes, tr("Yes"));
+    msgBox.setButtonText(QMessageBox::No, tr("No"));
+    // Turns out the layout box in the QMessageBox is a grid
+    // You can force the resize using a spacer this way:
+    QSpacerItem* horizontalSpacer = new QSpacerItem(400, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
+    QGridLayout* layout = (QGridLayout*)msgBox.layout();
+    layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
+    msgBox.setDefaultButton(default_val ? QMessageBox::Yes : QMessageBox::No);
+    return msgBox.exec() == QMessageBox::Yes;
+}
+
+/**
+ * For each repo, add the "server-url" property (inferred from account url),
+ * which would be used for http sync.
+ */
+void SeafileApplet::updateReposPropertyForHttpSync()
+{
+    std::vector<LocalRepo> repos;
+    if (rpc_client_->listLocalRepos(&repos) < 0) {
+        QTimer::singleShot(kIntervalForUpdateRepoProperty,
+                           this, SLOT(updateReposPropertyForHttpSync()));
+        return;
+    }
+
+    const std::vector<Account>& accounts = account_mgr_->accounts();
+    for (size_t i = 0; i < repos.size(); i++) {
+        const LocalRepo& repo = repos[i];
+        QString repo_server_url;
+        QString relay_addr;
+        if (rpc_client_->getRepoProperty(repo.id, kRepoServerUrlProperty, &repo_server_url) < 0) {
+            continue;
+        }
+        if (!repo_server_url.isEmpty()) {
+            continue;
+        }
+        if (rpc_client_->getRepoProperty(repo.id, kRepoRelayAddrProperty, &relay_addr) < 0) {
+            continue;
+        }
+        for (size_t i = 0; i < accounts.size(); i++) {
+            const Account& account = accounts[i];
+            if (account.serverUrl.host() == relay_addr) {
+                QUrl url(account.serverUrl);
+                url.setPath("/");
+                rpc_client_->setRepoProperty(repo.id, kRepoServerUrlProperty, url.toString());
+                break;
+            }
+        }
+    }
+}
+
+QVariant SeafileApplet::readPreconfigureEntry(const QString& key, const QVariant& default_value)
+{
+#ifdef Q_OS_WIN32
+    QVariant v = RegElement::getPreconfigureValue(key);
+    if (!v.isNull()) {
+        return v;
+    }
+#endif
+    QString configure_file = QDir::home().filePath(kSeafileConfigureFileName);
+    if (!QFileInfo(configure_file).exists())
+        return default_value;
+    QSettings setting(configure_file, QSettings::IniFormat);
+    setting.beginGroup(kSeafilePreconfigureGroupName);
+    QVariant value = setting.value(key, default_value);
+    setting.endGroup();
+    return value;
+}
+
+QString SeafileApplet::readPreconfigureExpandedString(const QString& key, const QString& default_value)
+{
+    QVariant retval = readPreconfigureEntry(key, default_value);
+    if (retval.isNull() || retval.type() != QVariant::String)
+        return QString();
+    return expandVars(retval.toString());
+}
+
+
+QString SeafileApplet::getText(QWidget *parent,
+                               const QString &title,
+                               const QString &label,
+                               QLineEdit::EchoMode mode,
+                               const QString &text,
+                               bool *ok,
+                               Qt::WindowFlags flags,
+                               Qt::InputMethodHints inputMethodHints)
+{
+    QInputDialog tmp_dialog;
+    // Get rid of the help button
+    if (flags == 0) {
+        flags = tmp_dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint;
+    }
+
+    return QInputDialog::getText(parent != nullptr ? parent : main_win_,
+                                 title,
+                                 label,
+                                 mode,
+                                 text,
+                                 ok,
+                                 flags,
+                                 inputMethodHints);
+}
+
+QString SeafileApplet::getUniqueClientId()
+{
+    static QString id;
+    if (!id.isEmpty()) {
+        return id;
+    }
+
+    // Id file path is `~/Seafile/.seafile-data/id`
+    QFile id_file(QDir(seafApplet->configurator()->seafileDir())
+                  .absoluteFilePath("id"));
+    if (!id_file.exists()) {
+        qWarning("id file not found, creating it");
+        // First migrate existing id from ccnet.conf General.ID
+        QString ccnet_conf_file = QDir(configurator_->ccnetDir()).absoluteFilePath("ccnet.conf");
+        QString ccnet_id;
+        if (QFile(ccnet_conf_file).exists()) {
+            QSettings ccnet_conf(ccnet_conf_file, QSettings::IniFormat);
+            ccnet_id = ccnet_conf.value("ID").toString();
+            if (ccnet_id.isEmpty()) {
+                ccnet_conf.beginGroup("General");
+                ccnet_id = ccnet_conf.value("ID", "").toString();
+            }
+        }
+
+        if (!ccnet_id.isEmpty()) {
+            id = ccnet_id;
+            qWarning("use existing ccnet id %s", toCStr(id));
+        } else {
+            srand(time(NULL));
+            while (id.length() < 40) {
+                int r = rand() % 0xff;
+                id += QString("%1").arg(r, 0, 16);
+            }
+            id = id.mid(0, 40);
+            qWarning("generated new device id %s", toCStr(id));
+        }
+
+        if (!id_file.open(QIODevice::WriteOnly)) {
+            errorAndExit(tr("failed to save client id"));
+            return "";
+        }
+
+        id_file.write(id.toUtf8().data());
+        return id;
+    }
+
+    if (!id_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        errorAndExit(tr("failed to access %1").arg(id_file.fileName()));
+        return "";
+    }
+
+    QTextStream input(&id_file);
+    input.setCodec("UTF-8");
+
+    if (input.atEnd()) {
+        errorAndExit(tr("incorrect client id"));
+        return "";
+    }
+
+    id = input.readLine().trimmed();
+    if (id.length() != 40) {
+        errorAndExit(tr("failed to read %1").arg(id_file.fileName()));
+        return "";
+    }
+
+    qWarning("read id from id file");
+    return id;
+}
+
+void SeafileApplet::onDaemonRestarted()
+{
+    qDebug("reviving rpc client when daemon is restarted");
+    if (rpc_client_) {
+        delete rpc_client_;
+    }
+
+    rpc_client_ = new SeafileRpcClient();
+    rpc_client_->tryConnectDaemon();
+}
diff --git a/src/seafile-applet.h b/src/seafile-applet.h
new file mode 100644 (file)
index 0000000..432c79a
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef SEAFILE_CLIENT_APPLET_H
+#define SEAFILE_CLIENT_APPLET_H
+
+#include <QObject>
+#include <QVariant>
+#include <QMessageBox>
+#include <QLineEdit>
+
+class Configurator;
+class DaemonManager;
+class SeafileRpcClient;
+class AccountManager;
+class MainWindow;
+class MessagePoller;
+class SeafileTrayIcon;
+class SettingsManager;
+class SettingsDialog;
+class CertsManager;
+class DataManager;
+
+
+/**
+ * The central class of seafile-client
+ */
+class SeafileApplet : QObject {
+    Q_OBJECT
+
+public:
+    SeafileApplet();
+    ~SeafileApplet();
+
+    void start();
+
+    void refreshQss();
+
+    void messageBox(const QString& msg, QWidget *parent=0);
+    void warningBox(const QString& msg, QWidget *parent=0);
+    bool yesOrNoBox(const QString& msg, QWidget *parent=0, bool default_val=true);
+    bool detailedYesOrNoBox(const QString& msg, const QString& detailed_text, QWidget *parent, bool default_val=true);
+    QMessageBox::StandardButton yesNoCancelBox(const QString& msg,
+                                               QWidget *parent,
+                                               QMessageBox::StandardButton default_btn);
+    bool yesOrCancelBox(const QString& msg, QWidget *parent, bool default_ok);
+
+    QString getText(QWidget *parent,
+                    const QString &title,
+                    const QString &label,
+                    QLineEdit::EchoMode mode = QLineEdit::Normal,
+                    const QString &text = QString(),
+                    bool *ok = 0,
+                    Qt::WindowFlags flags = 0,
+                    Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
+
+        // Show error in a messagebox and exit
+        void errorAndExit(const QString &error);
+    void restartApp();
+
+    // Read preconfigure settings
+    QVariant readPreconfigureEntry(const QString& key, const QVariant& default_value = QVariant());
+    // ExpandedVars String
+    QString readPreconfigureExpandedString(const QString& key, const QString& default_value = QString());
+
+    // Create a unique device id to replace obselete ccnet id
+    QString getUniqueClientId();
+
+    // accessors
+    AccountManager *accountManager() { return account_mgr_; }
+
+    SeafileRpcClient *rpcClient() { return rpc_client_; }
+
+    DaemonManager *daemonManager() { return daemon_mgr_; }
+
+    Configurator *configurator() { return configurator_; }
+
+    MainWindow *mainWindow() { return main_win_; }
+
+    SeafileTrayIcon *trayIcon() { return tray_icon_; }
+
+    SettingsDialog *settingsDialog() { return settings_dialog_; }
+
+    SettingsManager *settingsManager() { return settings_mgr_; }
+
+    CertsManager *certsManager() { return certs_mgr_; }
+
+    DataManager *dataManager() { return data_mgr_; }
+
+    bool started() { return started_; }
+    bool closingDown() { return in_exit_ || about_to_quit_; }
+
+private slots:
+    void onDaemonStarted();
+    void onDaemonRestarted();
+    void checkInitVDrive();
+    void updateReposPropertyForHttpSync();
+    void onAboutToQuit();
+
+private:
+    Q_DISABLE_COPY(SeafileApplet)
+
+    void initLog();
+
+    bool loadQss(const QString& path);
+
+    Configurator *configurator_;
+
+    AccountManager *account_mgr_;
+
+    DaemonManager *daemon_mgr_;
+
+    MainWindow* main_win_;
+
+    SeafileRpcClient *rpc_client_;
+
+    MessagePoller *message_poller_;
+
+    SeafileTrayIcon *tray_icon_;
+
+    SettingsDialog *settings_dialog_;
+
+    SettingsManager *settings_mgr_;
+
+    CertsManager *certs_mgr_;
+
+    DataManager *data_mgr_;
+
+    bool started_;
+
+    bool in_exit_;
+
+    QString style_;
+
+    bool is_pro_;
+
+    bool about_to_quit_;
+};
+
+/**
+ * The global SeafileApplet object
+ */
+extern SeafileApplet *seafApplet;
+
+#define STR(s)     #s
+#define STRINGIZE(x) STR(x)
+
+#endif // SEAFILE_CLIENT_APPLET_H
diff --git a/src/seahub-notifications-monitor.cpp b/src/seahub-notifications-monitor.cpp
new file mode 100644 (file)
index 0000000..421891a
--- /dev/null
@@ -0,0 +1,130 @@
+#include <QTimer>
+#include <QUrl>
+#include <QDesktopServices>
+
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "api/requests.h"
+#include "auto-login-service.h"
+
+#include "seahub-notifications-monitor.h"
+
+namespace {
+
+const int kRefreshSeahubMessagesInterval = 5000 * 60; // 5 min
+const char *kNotificationsUrl = "notification/list/";
+
+} // namespace
+
+
+SeahubNotificationsMonitor* SeahubNotificationsMonitor::singleton_;
+
+SeahubNotificationsMonitor* SeahubNotificationsMonitor::instance()
+{
+    if (singleton_ == NULL) {
+        static SeahubNotificationsMonitor instance;
+        singleton_ = &instance;
+    }
+
+    return singleton_;
+}
+
+SeahubNotificationsMonitor::SeahubNotificationsMonitor(QObject *parent)
+    : QObject(parent),
+      check_messages_req_(0),
+      in_refresh_(false),
+      unread_count_(0)
+{
+    refresh_timer_ = new QTimer(this);
+    connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refresh()));
+}
+
+void SeahubNotificationsMonitor::start()
+{
+    resetStatus();
+
+    refresh_timer_->start(kRefreshSeahubMessagesInterval);
+
+    connect(seafApplet->accountManager(), SIGNAL(accountsChanged()),
+            this, SLOT(onAccountChanged()));
+    refresh();
+}
+
+void SeahubNotificationsMonitor::onAccountChanged()
+{
+    refresh(true);
+}
+
+void SeahubNotificationsMonitor::resetStatus()
+{
+    setUnreadNotificationsCount(0);
+}
+
+void SeahubNotificationsMonitor::refresh()
+{
+    if (in_refresh_) {
+        return;
+    }
+
+    const Account& account = seafApplet->accountManager()->currentAccount();
+    if (!account.isValid()) {
+        resetStatus();
+        return;
+    }
+
+    in_refresh_ = true;
+
+    if (check_messages_req_) {
+        check_messages_req_->deleteLater();
+    }
+
+    check_messages_req_ = new GetUnseenSeahubNotificationsRequest(account);
+
+    connect(check_messages_req_, SIGNAL(success(int)),
+            this, SLOT(onRequestSuccess(int)));
+    connect(check_messages_req_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onRequestFailed(const ApiError&)));
+
+    check_messages_req_->send();
+}
+
+void SeahubNotificationsMonitor::onRequestFailed(const ApiError& error)
+{
+    in_refresh_ = false;
+}
+
+void SeahubNotificationsMonitor::onRequestSuccess(int count)
+{
+    in_refresh_ = false;
+    setUnreadNotificationsCount(count);
+}
+
+void SeahubNotificationsMonitor::refresh(bool force)
+{
+    if (force) {
+        resetStatus();
+        in_refresh_ = false;
+    }
+
+    refresh();
+}
+
+void SeahubNotificationsMonitor::openNotificationsPageInBrowser()
+{
+    const Account& account = seafApplet->accountManager()->currentAccount();
+    if (!account.isValid()) {
+        return;
+    }
+
+    AutoLoginService::instance()->startAutoLogin(kNotificationsUrl);
+
+    resetStatus();
+}
+
+void SeahubNotificationsMonitor::setUnreadNotificationsCount(int count)
+{
+    if (unread_count_ != count) {
+        unread_count_ = count;
+        emit notificationsChanged();
+    }
+}
diff --git a/src/seahub-notifications-monitor.h b/src/seahub-notifications-monitor.h
new file mode 100644 (file)
index 0000000..3fe9708
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef SEAFILE_CLIENT_SEAHUB_MESSAGES_MONITOR_
+#define SEAFILE_CLIENT_SEAHUB_MESSAGES_MONITOR_
+
+#include <QObject>
+
+class QTimer;
+
+class ApiError;
+class GetUnseenSeahubNotificationsRequest;
+
+class SeahubNotificationsMonitor : public QObject
+{
+    Q_OBJECT
+public:
+    static SeahubNotificationsMonitor* instance();
+
+    void start();
+    void refresh(bool force);
+
+    int getUnreadNotifications() const { return unread_count_; }
+
+    void openNotificationsPageInBrowser();
+
+public slots:
+    void refresh();
+
+signals:
+    void notificationsChanged();
+
+private slots:
+    void onRequestSuccess(int count);
+    void onRequestFailed(const ApiError& error);
+    void onAccountChanged();
+
+private:
+    SeahubNotificationsMonitor(QObject *parent=0);
+    static SeahubNotificationsMonitor *singleton_;
+
+    void resetStatus();
+    void setUnreadNotificationsCount(int count);
+
+    QTimer *refresh_timer_;
+    GetUnseenSeahubNotificationsRequest *check_messages_req_;
+    bool in_refresh_;
+
+    int unread_count_;
+};
+
+#endif // SEAFILE_CLIENT_SEAHUB_MESSAGES_MONITOR_
diff --git a/src/server-status-service.cpp b/src/server-status-service.cpp
new file mode 100644 (file)
index 0000000..3e23ff6
--- /dev/null
@@ -0,0 +1,173 @@
+#include <QTimer>
+
+#include "server-status-service.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+
+namespace {
+
+// const int kRefreshInterval = 3 * 60 * 1000; // 3 min
+// const int kRefreshIntervalForUnconnected = 30 * 1000; // 30 sec
+
+}
+
+SINGLETON_IMPL(ServerStatusService)
+
+ServerStatusService::ServerStatusService(QObject *parent)
+    : QObject(parent)
+{
+    refresh_timer_ = new QTimer(this);
+    refresh_unconnected_timer_ = new QTimer(this);
+    connect(refresh_timer_, SIGNAL(timeout()),
+            this, SLOT(refresh()));
+    connect(refresh_unconnected_timer_, SIGNAL(timeout()),
+            this, SLOT(refreshUnconnected()));
+    refresh();
+}
+
+void ServerStatusService::start()
+{
+    // refresh_timer_->start(kRefreshInterval);
+    // refresh_unconnected_timer_->start(kRefreshIntervalForUnconnected);
+}
+
+void ServerStatusService::stop()
+{
+    refresh_timer_->stop();
+    refresh_unconnected_timer_->stop();
+}
+
+void ServerStatusService::refresh(bool only_refresh_unconnected)
+{
+    const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+    for (size_t i = 0; i < accounts.size(); i++) {
+        const QUrl& url = accounts[i].serverUrl;
+        if (!accounts[i].isValid()) {
+            // No need to ping the server if account has already logged out
+            statuses_.remove(url.host());
+            emit serverStatusChanged();
+            continue;
+        }
+        if (requests_.contains(url.host())) {
+            continue;
+        }
+
+        if (!statuses_.contains(url.host())) {
+            statuses_[url.host()] = ServerStatus(url, true);
+        }
+
+        if (only_refresh_unconnected && isServerConnected(url)) {
+            continue;
+        }
+        pingServer(url);
+    }
+}
+
+void ServerStatusService::pingServer(const QUrl& url)
+{
+    PingServerRequest *req = new PingServerRequest(url);
+    connect(req, SIGNAL(success()),
+            this, SLOT(onPingServerSuccess()));
+    connect(req, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onPingServerFailed()));
+    req->send();
+    requests_[url.host()] = req;
+}
+
+
+void ServerStatusService::onPingServerSuccess()
+{
+    PingServerRequest *req = (PingServerRequest *)sender();
+    statuses_[req->url().host()] = ServerStatus(req->url(), true);
+    emit serverStatusChanged();
+    requests_.take(req->url().host())->deleteLater();
+}
+
+void ServerStatusService::onPingServerFailed()
+{
+    PingServerRequest *req = (PingServerRequest *)sender();
+    statuses_[req->url().host()] = ServerStatus(req->url(), false);
+    emit serverStatusChanged();
+    requests_.take(req->url().host())->deleteLater();
+}
+
+bool ServerStatusService::allServersConnected() const
+{
+    foreach (const ServerStatus& status, statuses()) {
+        if (!status.connected) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool ServerStatusService::allServersDisconnected() const
+{
+    if (statuses_.isEmpty()) {
+        return false;
+    }
+    foreach (const ServerStatus& status, statuses()) {
+        if (status.connected) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+bool ServerStatusService::isServerConnected(const QUrl& url) const
+{
+    return statuses_.value(url.host()).connected;
+}
+
+void ServerStatusService::updateOnSuccessfullRequest(const QUrl& url)
+{
+    updateOnRequestFinished(url, true);
+}
+
+void ServerStatusService::updateOnFailedRequest(const QUrl& url)
+{
+    updateOnRequestFinished(url, false);
+}
+
+void ServerStatusService::updateOnRequestFinished(const QUrl& url, bool no_network_error)
+{
+    if (seafApplet->closingDown()) {
+        return;
+    }
+    bool found = false;
+    const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+    for (size_t i = 0; i < accounts.size(); i++) {
+        if (url.host() == accounts[i].serverUrl.host()) {
+            if (!accounts[i].isValid()) {
+                // No need to update the server status if account has already logged out
+                statuses_.remove(url.host());
+                emit serverStatusChanged();
+                continue;
+            }
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        qWarning("ServerStatusService: ignore request for host \"%s\"", url.host().toUtf8().data());
+        return;
+    }
+
+    bool changed = false;
+    if (statuses_.contains(url.host())) {
+        const ServerStatus& status = statuses_[url.host()];
+        if (status.connected != no_network_error) {
+            changed = true;
+        }
+    }
+    statuses_[url.host()] = ServerStatus(url, no_network_error);
+
+    if (changed) {
+        emit serverStatusChanged();
+    }
+}
diff --git a/src/server-status-service.h b/src/server-status-service.h
new file mode 100644 (file)
index 0000000..305a08e
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef SEAFILE_CLIENT_SERVER_STATUS_SERVICE_H
+#define SEAFILE_CLIENT_SERVER_STATUS_SERVICE_H
+
+#include <QObject>
+#include <QList>
+#include <QUrl>
+#include <QHash>
+
+#include "utils/singleton.h"
+
+class QTimer;
+
+class PingServerRequest;
+class ApiError;
+
+class ServerStatus {
+public:
+    ServerStatus() {}
+    ServerStatus(const QUrl& url, bool connected):
+        url(url),
+        connected(connected) {}
+
+    QUrl url;
+    bool connected;
+};
+
+class ServerStatusService : public QObject
+{
+    Q_OBJECT
+    SINGLETON_DEFINE(ServerStatusService)
+public:
+    void start();
+    void stop();
+
+    // accessors
+    const QList<ServerStatus> statuses() const { return statuses_.values(); }
+
+    bool allServersConnected() const;
+    bool allServersDisconnected() const;
+
+public slots:
+    void refresh(bool only_refresh_unconnected=false);
+    void refreshUnconnected() { refresh(true); }
+    void updateOnSuccessfullRequest(const QUrl& url);
+    void updateOnFailedRequest(const QUrl& url);
+
+private slots:
+    void onPingServerSuccess();
+    void onPingServerFailed();
+
+signals:
+    void serverStatusChanged();
+
+private:
+    Q_DISABLE_COPY(ServerStatusService)
+    ServerStatusService(QObject *parent=0);
+
+    void pingServer(const QUrl& url);
+    bool isServerConnected(const QUrl& url) const;
+    void updateOnRequestFinished(const QUrl& url, bool no_network_error);
+
+    QTimer *refresh_timer_;
+    QTimer *refresh_unconnected_timer_;
+
+    QHash<QString, ServerStatus> statuses_;
+    QHash<QString, PingServerRequest *> requests_;
+};
+
+
+#endif // SEAFILE_CLIENT_SERVER_STATUS_SERVICE_H
diff --git a/src/settings-mgr.cpp b/src/settings-mgr.cpp
new file mode 100644 (file)
index 0000000..9fe7b48
--- /dev/null
@@ -0,0 +1,757 @@
+#include <QHostInfo>
+#include <QNetworkProxy>
+#include <QNetworkProxyQuery>
+#include <QSettings>
+#include <QThreadPool>
+#include <QTimer>
+
+#include "utils/utils.h"
+#include "utils/utils-mac.h"
+#include "seafile-applet.h"
+#include "ui/tray-icon.h"
+#include "rpc/rpc-client.h"
+#include "utils/utils.h"
+#include "network-mgr.h"
+#include "ui/main-window.h"
+#include "account-mgr.h"
+
+#if defined(Q_OS_WIN32)
+#include "utils/registry.h"
+#endif
+
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+#include "finder-sync/finder-sync.h"
+#endif
+
+#include "settings-mgr.h"
+
+namespace
+{
+const char *kHideMainWindowWhenStarted = "hideMainWindowWhenStarted";
+const char *kHideDockIcon = "hideDockIcon";
+const char *kEnableSyncingWithExistingFolder = "syncingWithExistingFolder";
+const char *kBehaviorGroup = "Behavior";
+
+// const char *kDefaultLibraryAlreadySetup = "defaultLibraryAlreadySetup";
+// const char *kStatusGroup = "Status";
+
+const char *kSettingsGroup = "Settings";
+const char *kComputerName = "computerName";
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+const char *kFinderSync = "finderSync";
+#endif // HAVE_FINDER_SYNC_SUPPORT
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+const char *kLastShibUrl = "lastShiburl";
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+const char *kUseProxy = "use_proxy";
+const char *kUseSystemProxy = "use_system_proxy";
+const char *kProxyType = "proxy_type";
+const char *kProxyAddr = "proxy_addr";
+const char *kProxyPort = "proxy_port";
+const char *kProxyUsername = "proxy_username";
+const char *kProxyPassword = "proxy_password";
+
+const int kCheckSystemProxyIntervalMSecs = 5 * 1000;
+
+
+#ifdef Q_OS_WIN32
+QString softwareSeafile()
+{
+    return QString("SOFTWARE\\%1").arg(getBrand());
+}
+#endif
+
+
+bool getSystemProxyForUrl(const QUrl &url, QNetworkProxy *proxy)
+{
+    QNetworkProxyQuery query(url);
+    bool use_proxy = true;
+    QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(query);
+
+    // printf("list of proxies: %d\n", proxies.size());
+    // foreach (const QNetworkProxy &proxy, proxies) {
+    //     static int i = 0;
+    //     printf("[proxy number %d] %d %s:%d %s %s \n", i++, (int)proxy.type(),
+    //            proxy.hostName().toUtf8().data(), proxy.port(),
+    //            proxy.user().toUtf8().data(),
+    //            proxy.password().toUtf8().data());
+    // }
+
+    if (proxies.empty()) {
+        use_proxy = false;
+    } else {
+        *proxy = proxies[0];
+        if (proxy->type() == QNetworkProxy::NoProxy ||
+            proxy->type() == QNetworkProxy::DefaultProxy ||
+            proxy->type() == QNetworkProxy::FtpCachingProxy) {
+            use_proxy = false;
+        }
+
+        if (proxy->hostName().isEmpty() || proxy->port() == 0) {
+            use_proxy = false;
+        }
+    }
+
+    return use_proxy;
+}
+
+
+} // namespace
+
+
+SettingsManager::SettingsManager()
+    : auto_sync_(true),
+      bubbleNotifycation_(true),
+      autoStart_(false),
+      allow_invalid_worktree_(false),
+      allow_repo_not_found_on_server_(false),
+      sync_extra_temp_file_(false),
+      maxDownloadRatio_(0),
+      maxUploadRatio_(0),
+      verify_http_sync_cert_disabled_(false),
+      current_proxy_(SeafileProxy())
+{
+    check_system_proxy_timer_ = new QTimer(this);
+    connect(check_system_proxy_timer_, SIGNAL(timeout()), this, SLOT(checkSystemProxy()));
+}
+
+void SettingsManager::loadSettings()
+{
+    QString str;
+    int value;
+
+    if (seafApplet->rpcClient()->seafileGetConfig("notify_sync", &str) >= 0)
+        bubbleNotifycation_ = (str == "off") ? false : true;
+
+    if (seafApplet->rpcClient()->seafileGetConfigInt("download_limit",
+                                                     &value) >= 0)
+        maxDownloadRatio_ = value >> 10;
+
+    if (seafApplet->rpcClient()->seafileGetConfigInt("upload_limit",
+                                                     &value) >= 0)
+        maxUploadRatio_ = value >> 10;
+
+    if (seafApplet->rpcClient()->seafileGetConfig("allow_invalid_worktree",
+                                                  &str) >= 0)
+        allow_invalid_worktree_ = (str == "true") ? true : false;
+
+    if (seafApplet->rpcClient()->seafileGetConfig("sync_extra_temp_file",
+                                                  &str) >= 0)
+        sync_extra_temp_file_ = (str == "true") ? true : false;
+
+    if (seafApplet->rpcClient()->seafileGetConfig(
+            "allow_repo_not_found_on_server", &str) >= 0)
+        allow_repo_not_found_on_server_ = (str == "true") ? true : false;
+
+    if (seafApplet->rpcClient()->seafileGetConfig("disable_verify_certificate",
+                                                  &str) >= 0)
+        verify_http_sync_cert_disabled_ = (str == "true") ? true : false;
+
+    loadProxySettings();
+    applyProxySettings();
+
+    autoStart_ = get_seafile_auto_start();
+
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+    // try to do a reinstall, or we may use findersync somewhere else
+    // this action won't stop findersync if running already
+    FinderSyncExtensionHelper::reinstall();
+
+    // try to sync finder sync extension settings with the actual settings
+    // i.e. enabling the finder sync if the setting is true
+    setFinderSyncExtension(getFinderSyncExtension());
+#endif // HAVE_FINDER_SYNC_SUPPORT
+
+
+#ifdef Q_OS_WIN32
+    RegElement reg(HKEY_CURRENT_USER, softwareSeafile(), "ShellExtDisabled",
+                   "");
+    shell_ext_enabled_ = !reg.exists();
+#endif
+}
+
+void SettingsManager::loadProxySettings()
+{
+    SeafileProxy proxy;
+
+    QString use_proxy;
+    seafApplet->rpcClient()->seafileGetConfig(kUseProxy, &use_proxy);
+    if (use_proxy != "true") {
+        return;
+    }
+    QString use_system_proxy;
+    seafApplet->rpcClient()->seafileGetConfig(kUseSystemProxy, &use_system_proxy);
+    if (use_system_proxy == "true") {
+        current_proxy_.type = SystemProxy;
+        return;
+    }
+
+    QString proxy_type;
+    QString proxy_host;
+    int proxy_port;
+    QString proxy_username;
+    QString proxy_password;
+
+    if (seafApplet->rpcClient()->seafileGetConfig(kProxyAddr, &proxy_host) <
+        0) {
+        return;
+    }
+    if (seafApplet->rpcClient()->seafileGetConfigInt(kProxyPort, &proxy_port) <
+        0) {
+        return;
+    }
+    if (seafApplet->rpcClient()->seafileGetConfig(kProxyType, &proxy_type) <
+        0) {
+        return;
+    }
+    if (proxy_type == "http") {
+        if (seafApplet->rpcClient()->seafileGetConfig(kProxyUsername,
+                                                      &proxy_username) < 0) {
+            return;
+        }
+        if (seafApplet->rpcClient()->seafileGetConfig(kProxyPassword,
+                                                      &proxy_password) < 0) {
+            return;
+        }
+        proxy.type = HttpProxy;
+        proxy.host = proxy_host;
+        proxy.port = proxy_port;
+        proxy.username = proxy_username;
+        proxy.password = proxy_password;
+
+    } else if (proxy_type == "socks") {
+        proxy.type = SocksProxy;
+        proxy.host = proxy_host;
+        proxy.port = proxy_port;
+    } else if (!proxy_type.isEmpty()) {
+        qWarning("Unsupported proxy_type %s", proxy_type.toUtf8().data());
+        return;
+    }
+
+    current_proxy_ = proxy;
+}
+
+
+void SettingsManager::setAutoSync(bool auto_sync)
+{
+    if (seafApplet->rpcClient()->setAutoSync(auto_sync) < 0) {
+        // Error
+        return;
+    }
+    auto_sync_ = auto_sync;
+    seafApplet->trayIcon()->setState(
+        auto_sync ? SeafileTrayIcon::STATE_DAEMON_UP
+                  : SeafileTrayIcon::STATE_DAEMON_AUTOSYNC_DISABLED);
+    emit autoSyncChanged(auto_sync);
+}
+
+void SettingsManager::setNotify(bool notify)
+{
+    if (bubbleNotifycation_ != notify) {
+        if (seafApplet->rpcClient()->seafileSetConfig(
+                "notify_sync", notify ? "on" : "off") < 0) {
+            // Error
+            return;
+        }
+        bubbleNotifycation_ = notify;
+    }
+}
+
+void SettingsManager::setAutoStart(bool autoStart)
+{
+    if (autoStart_ != autoStart) {
+        if (set_seafile_auto_start(autoStart) >= 0)
+            autoStart_ = autoStart;
+    }
+}
+
+void SettingsManager::setMaxDownloadRatio(unsigned int ratio)
+{
+    if (maxDownloadRatio_ != ratio) {
+        if (seafApplet->rpcClient()->setDownloadRateLimit(ratio << 10) < 0) {
+            // Error
+            return;
+        }
+        maxDownloadRatio_ = ratio;
+    }
+}
+
+void SettingsManager::setMaxUploadRatio(unsigned int ratio)
+{
+    if (maxUploadRatio_ != ratio) {
+        if (seafApplet->rpcClient()->setUploadRateLimit(ratio << 10) < 0) {
+            // Error
+            return;
+        }
+        maxUploadRatio_ = ratio;
+    }
+}
+
+bool SettingsManager::hideMainWindowWhenStarted()
+{
+    QSettings settings;
+    bool hide;
+
+    settings.beginGroup(kBehaviorGroup);
+    hide = settings.value(kHideMainWindowWhenStarted, false).toBool();
+    settings.endGroup();
+
+    return hide;
+}
+
+void SettingsManager::setHideMainWindowWhenStarted(bool hide)
+{
+    QSettings settings;
+
+    settings.beginGroup(kBehaviorGroup);
+    settings.setValue(kHideMainWindowWhenStarted, hide);
+    settings.endGroup();
+}
+
+bool SettingsManager::hideDockIcon()
+{
+    QSettings settings;
+    bool hide;
+
+    settings.beginGroup(kBehaviorGroup);
+    hide = settings.value(kHideDockIcon, false).toBool();
+    settings.endGroup();
+    return hide;
+}
+
+void SettingsManager::setHideDockIcon(bool hide)
+{
+    QSettings settings;
+
+    settings.beginGroup(kBehaviorGroup);
+    settings.setValue(kHideDockIcon, hide);
+    settings.endGroup();
+
+    set_seafile_dock_icon_style(hide);
+#ifdef Q_OS_MAC
+    // for UIElement application, the main window might sink
+    // under many applications
+    // this will force it to stand before all
+    utils::mac::orderFrontRegardless(seafApplet->mainWindow()->winId());
+#endif
+}
+
+// void SettingsManager::setDefaultLibraryAlreadySetup()
+// {
+//     QSettings settings;
+
+//     settings.beginGroup(kStatusGroup);
+//     settings.setValue(kDefaultLibraryAlreadySetup, true);
+//     settings.endGroup();
+// }
+
+
+// bool SettingsManager::defaultLibraryAlreadySetup()
+// {
+//     QSettings settings;
+//     bool done;
+
+//     settings.beginGroup(kStatusGroup);
+//     done = settings.value(kDefaultLibraryAlreadySetup, false).toBool();
+//     settings.endGroup();
+
+//     return done;
+// }
+
+void SettingsManager::removeAllSettings()
+{
+    QSettings settings;
+    settings.clear();
+
+#if defined(Q_OS_WIN32)
+    RegElement::removeRegKey(HKEY_CURRENT_USER, "SOFTWARE", getBrand());
+#endif
+}
+
+void SettingsManager::setAllowInvalidWorktree(bool val)
+{
+    if (allow_invalid_worktree_ != val) {
+        if (seafApplet->rpcClient()->seafileSetConfig(
+                "allow_invalid_worktree", val ? "true" : "false") < 0) {
+            // Error
+            return;
+        }
+        allow_invalid_worktree_ = val;
+    }
+}
+
+void SettingsManager::setSyncExtraTempFile(bool sync)
+{
+    if (sync_extra_temp_file_ != sync) {
+        if (seafApplet->rpcClient()->seafileSetConfig(
+                "sync_extra_temp_file", sync ? "true" : "false") < 0) {
+            // Error
+            return;
+        }
+        sync_extra_temp_file_ = sync;
+    }
+}
+
+void SettingsManager::getProxy(QNetworkProxy *proxy) const
+{
+    current_proxy_.toQtNetworkProxy(proxy);
+    return;
+}
+
+void SettingsManager::SeafileProxy::toQtNetworkProxy(QNetworkProxy *proxy) const
+{
+    if (type == NoProxy) {
+        proxy->setType(QNetworkProxy::NoProxy);
+        return;
+    }
+    proxy->setType(type == HttpProxy ? QNetworkProxy::HttpProxy
+                                     : QNetworkProxy::Socks5Proxy);
+    proxy->setHostName(host);
+    proxy->setPort(port);
+    if (type == HttpProxy && !username.isEmpty() && !password.isEmpty()) {
+        proxy->setUser(username);
+        proxy->setPassword(password);
+    }
+}
+
+SettingsManager::SeafileProxy SettingsManager::SeafileProxy::fromQtNetworkProxy(
+    const QNetworkProxy &proxy)
+{
+    SeafileProxy sproxy;
+    if (proxy.type() == QNetworkProxy::NoProxy ||
+        proxy.type() == QNetworkProxy::DefaultProxy) {
+        sproxy.type = NoProxy;
+        return sproxy;
+    }
+
+    sproxy.host = proxy.hostName();
+    sproxy.port = proxy.port();
+
+    if (proxy.type() == QNetworkProxy::HttpProxy) {
+        sproxy.type = HttpProxy;
+        sproxy.username = proxy.user();
+        sproxy.password = proxy.password();
+    } else if (proxy.type() == QNetworkProxy::Socks5Proxy) {
+        sproxy.type = SocksProxy;
+    }
+
+    return sproxy;
+}
+
+bool SettingsManager::SeafileProxy::operator==(const SeafileProxy &rhs) const
+{
+    if (type != rhs.type) {
+        return false;
+    }
+    if (type == NoProxy || type == SystemProxy) {
+        return true;
+    } else if (type == HttpProxy) {
+        return host == rhs.host && port == rhs.port &&
+               username == rhs.username && password == rhs.password;
+    } else {
+        // socks proxy
+        return host == rhs.host && port == rhs.port;
+    }
+}
+
+void SettingsManager::setProxy(const SeafileProxy &proxy)
+{
+    if (proxy == current_proxy_) {
+        return;
+    }
+    current_proxy_ = proxy;
+
+    writeProxySettingsToDaemon(proxy);
+    applyProxySettings();
+}
+
+void SettingsManager::applyProxySettings()
+{
+    if (current_proxy_.type == SystemProxy) {
+        QNetworkProxyFactory::setUseSystemConfiguration(true);
+        if (!check_system_proxy_timer_->isActive()) {
+            check_system_proxy_timer_->start(kCheckSystemProxyIntervalMSecs);
+        }
+        return;
+    } else {
+        QNetworkProxyFactory::setUseSystemConfiguration(false);
+        if (check_system_proxy_timer_->isActive()) {
+            check_system_proxy_timer_->stop();
+        }
+
+        if (current_proxy_.type == NoProxy) {
+            QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
+        }
+    }
+
+    QNetworkProxy proxy;
+    getProxy(&proxy);
+    NetworkManager::instance()->applyProxy(proxy);
+}
+
+void SettingsManager::writeProxySettingsToDaemon(const SeafileProxy &proxy)
+{
+    SeafileRpcClient *rpc = seafApplet->rpcClient();
+    if (proxy.type == NoProxy) {
+        rpc->seafileSetConfig(kUseProxy, "false");
+        return;
+    }
+
+    rpc->seafileSetConfig(kUseProxy, "true");
+    if (proxy.type == SystemProxy) {
+        rpc->seafileSetConfig(kUseSystemProxy, "true");
+        return;
+    } else {
+        rpc->seafileSetConfig(kUseSystemProxy, "false");
+    }
+
+    writeProxyDetailsToDaemon(proxy);
+}
+
+void SettingsManager::writeProxyDetailsToDaemon(const SeafileProxy& proxy)
+{
+    Q_ASSERT(proxy.type != NoProxy && proxy.type != SystemProxy);
+    SeafileRpcClient *rpc = seafApplet->rpcClient();
+    QString type = proxy.type == HttpProxy ? "http" : "socks";
+    rpc->seafileSetConfig(kProxyType, type);
+    rpc->seafileSetConfig(kProxyAddr, proxy.host.toUtf8().data());
+    rpc->seafileSetConfigInt(kProxyPort, proxy.port);
+    if (type == "http") {
+        rpc->seafileSetConfig(kProxyUsername, proxy.username.toUtf8().data());
+        rpc->seafileSetConfig(kProxyPassword, proxy.password.toUtf8().data());
+    }
+}
+
+void SettingsManager::setAllowRepoNotFoundOnServer(bool val)
+{
+    if (allow_repo_not_found_on_server_ != val) {
+        if (seafApplet->rpcClient()->seafileSetConfig(
+                "allow_repo_not_found_on_server", val ? "true" : "false") < 0) {
+            // Error
+            return;
+        }
+        allow_repo_not_found_on_server_ = val;
+    }
+}
+
+void SettingsManager::setHttpSyncCertVerifyDisabled(bool disabled)
+{
+    if (verify_http_sync_cert_disabled_ != disabled) {
+        if (seafApplet->rpcClient()->seafileSetConfig(
+                "disable_verify_certificate", disabled ? "true" : "false") <
+            0) {
+            // Error
+            return;
+        }
+        verify_http_sync_cert_disabled_ = disabled;
+    }
+}
+
+bool SettingsManager::isEnableSyncingWithExistingFolder() const
+{
+    bool enabled;
+    QSettings settings;
+
+    settings.beginGroup(kBehaviorGroup);
+    enabled = settings.value(kEnableSyncingWithExistingFolder, false).toBool();
+    settings.endGroup();
+
+    return enabled;
+}
+
+void SettingsManager::setEnableSyncingWithExistingFolder(bool enabled)
+{
+    QSettings settings;
+
+    settings.beginGroup(kBehaviorGroup);
+    settings.setValue(kEnableSyncingWithExistingFolder, enabled);
+    settings.endGroup();
+}
+
+QString SettingsManager::getComputerName()
+{
+    QSettings settings;
+    QString name;
+
+    QString default_computer_Name = QHostInfo::localHostName();
+
+    settings.beginGroup(kSettingsGroup);
+    name = settings.value(kComputerName, default_computer_Name).toString();
+    settings.endGroup();
+
+    return name;
+}
+
+void SettingsManager::setComputerName(const QString &computerName)
+{
+    QSettings settings;
+    settings.beginGroup(kSettingsGroup);
+    settings.setValue(kComputerName, computerName);
+    settings.endGroup();
+
+    seafApplet->rpcClient()->seafileSetConfig("client_name", computerName);
+}
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+QString SettingsManager::getLastShibUrl()
+{
+    QSettings settings;
+    QString url;
+
+    settings.beginGroup(kSettingsGroup);
+    url = settings.value(kLastShibUrl, "").toString();
+    settings.endGroup();
+
+    return url;
+}
+
+void SettingsManager::setLastShibUrl(const QString &url)
+{
+    QSettings settings;
+    settings.beginGroup(kSettingsGroup);
+    settings.setValue(kLastShibUrl, url);
+    settings.endGroup();
+}
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+bool SettingsManager::getFinderSyncExtension() const
+{
+    QSettings settings;
+    bool enabled;
+
+    settings.beginGroup(kSettingsGroup);
+    enabled = settings.value(kFinderSync, true).toBool();
+    settings.endGroup();
+
+    return enabled;
+}
+bool SettingsManager::getFinderSyncExtensionAvailable() const
+{
+    return FinderSyncExtensionHelper::isInstalled();
+}
+void SettingsManager::setFinderSyncExtension(bool enabled)
+{
+    QSettings settings;
+
+    settings.beginGroup(kSettingsGroup);
+    settings.setValue(kFinderSync, enabled);
+    settings.endGroup();
+
+    // if setting operation fails
+    if (!getFinderSyncExtensionAvailable()) {
+        qWarning("Unable to find FinderSync Extension");
+    } else if (enabled != FinderSyncExtensionHelper::isEnabled() &&
+               !FinderSyncExtensionHelper::setEnable(enabled)) {
+        qWarning("Unable to enable FinderSync Extension");
+    }
+}
+#endif // HAVE_FINDER_SYNC_SUPPORT
+
+#ifdef Q_OS_WIN32
+void SettingsManager::setShellExtensionEnabled(bool enabled)
+{
+    shell_ext_enabled_ = enabled;
+
+    RegElement reg1(HKEY_CURRENT_USER, softwareSeafile(), "", "");
+    RegElement reg2(HKEY_CURRENT_USER, softwareSeafile(), "ShellExtDisabled",
+                    "1");
+    if (enabled) {
+        reg2.remove();
+    } else {
+        reg1.add();
+        reg2.add();
+    }
+}
+#endif // Q_OS_WIN32
+
+
+void SettingsManager::writeSystemProxyInfo(const QUrl &url,
+                                           const QString &file_path)
+{
+    QNetworkProxy proxy;
+    bool use_proxy = getSystemProxyForUrl(url, &proxy);
+
+    QString content;
+    if (use_proxy) {
+        QString type;
+        if (proxy.type() == QNetworkProxy::HttpProxy ||
+            proxy.type() == QNetworkProxy::HttpCachingProxy) {
+            type = "http";
+        } else {
+            type = "socks";
+        }
+        QString json_content =
+            "{\"type\": \"%1\", \"addr\": \"%2\", \"port\": %3, \"username\": "
+            "\"%4\", \"password\": \"%5\"}";
+        content = json_content.arg(type)
+                      .arg(proxy.hostName())
+                      .arg(proxy.port())
+                      .arg(proxy.user())
+                      .arg(proxy.password());
+    } else {
+        content = "{\"type\": \"none\"}";
+    }
+
+    QFile system_proxy_txt(file_path);
+    if (!system_proxy_txt.open(QIODevice::WriteOnly)) {
+        return;
+    }
+
+    system_proxy_txt.write(content.toUtf8().data());
+}
+
+void SettingsManager::checkSystemProxy()
+{
+    if (current_proxy_.type != SystemProxy) {
+        // qDebug ("current proxy is not system proxy, return\n");
+        return;
+    }
+
+    const Account &account = seafApplet->accountManager()->currentAccount();
+    if (!account.isValid()) {
+        return;
+    }
+
+    SystemProxyPoller *poller = new SystemProxyPoller(account.serverUrl);
+    connect(poller, SIGNAL(systemProxyPolled(const QNetworkProxy &)), this,
+            SLOT(onSystemProxyPolled(const QNetworkProxy &)));
+
+    QThreadPool::globalInstance()->start(poller);
+}
+
+
+void SettingsManager::onSystemProxyPolled(const QNetworkProxy &system_proxy)
+{
+    if (current_proxy_.type != SystemProxy) {
+        return;
+    }
+    if (last_system_proxy_ == system_proxy) {
+        // qDebug ("system proxy not changed\n");
+        return;
+    }
+    // qDebug ("system proxy changed\n");
+    last_system_proxy_ = system_proxy;
+    SeafileProxy proxy = SeafileProxy::fromQtNetworkProxy(system_proxy);
+    if (proxy.type == NoProxy) {
+        // qDebug ("system proxy changed to no proxy\n");
+        seafApplet->rpcClient()->seafileSetConfig(kProxyType, "none");
+    } else {
+        writeProxyDetailsToDaemon(proxy);
+    }
+}
+
+SystemProxyPoller::SystemProxyPoller(const QUrl &url) : url_(url)
+{
+}
+
+void SystemProxyPoller::run()
+{
+    QNetworkProxy proxy;
+    bool use_proxy = getSystemProxyForUrl(url_, &proxy);
+    if (!use_proxy) {
+        proxy.setType(QNetworkProxy::NoProxy);
+    }
+    emit systemProxyPolled(proxy);
+}
diff --git a/src/settings-mgr.h b/src/settings-mgr.h
new file mode 100644 (file)
index 0000000..f37a8bc
--- /dev/null
@@ -0,0 +1,172 @@
+#ifndef SEAFILE_CLIENT_SETTINGS_MANAGER_H
+#define SEAFILE_CLIENT_SETTINGS_MANAGER_H
+
+#include <QObject>
+#include <QRunnable>
+#include <QUrl>
+#include <QNetworkProxy>
+
+/**
+ * Settings Manager handles seafile client user settings & preferences
+ */
+class QTimer;
+
+class SettingsManager : public QObject {
+    Q_OBJECT
+
+public:
+    enum ProxyType {
+        NoProxy = 0,
+        HttpProxy = 1,
+        SocksProxy = 2,
+        SystemProxy = 3
+    };
+
+    struct SeafileProxy {
+        ProxyType type;
+
+        QString host;
+        int port;
+        QString username;
+        QString password;
+
+        SeafileProxy(ProxyType _type = NoProxy,
+                     const QString _host = QString(),
+                     int _port = 0,
+                     const QString& _username = QString(),
+                     const QString& _password = QString())
+            : type(_type),
+              host(_host),
+              port(_port),
+              username(_username),
+              password(_password)
+        {
+        }
+
+        void toQtNetworkProxy(QNetworkProxy *proxy) const;
+
+        bool operator==(const SeafileProxy& rhs) const;
+        bool operator!=(const SeafileProxy& rhs) const { return !(*this == rhs); };
+
+        static SeafileProxy fromQtNetworkProxy(const QNetworkProxy& proxy);
+    };
+
+    SettingsManager();
+
+    void loadSettings();
+    void setAutoSync(bool);
+
+    bool autoSync() { return auto_sync_; }
+
+    bool notify() { return bubbleNotifycation_; }
+    bool autoStart() { return autoStart_; }
+    unsigned int maxDownloadRatio() { return maxDownloadRatio_; }
+    unsigned int maxUploadRatio() { return maxUploadRatio_; }
+    bool allowInvalidWorktree() { return allow_invalid_worktree_; }
+    bool syncExtraTempFile() { return sync_extra_temp_file_; }
+
+    void getProxy(QNetworkProxy *proxy) const;
+    SeafileProxy getProxy() const { return current_proxy_; };
+
+    void setNotify(bool notify);
+    void setAutoStart(bool autoStart);
+    void setMaxDownloadRatio(unsigned int ratio);
+    void setMaxUploadRatio(unsigned int ratio);
+    void setAllowInvalidWorktree(bool val);
+    void setSyncExtraTempFile(bool sync);
+    void setProxy(const SeafileProxy& proxy);
+
+    bool hideMainWindowWhenStarted();
+    void setHideMainWindowWhenStarted(bool hide);
+
+    bool hideDockIcon();
+    void setHideDockIcon(bool hide);
+
+    // bool defaultLibraryAlreadySetup();
+    // void setDefaultLibraryAlreadySetup();
+
+    void setAllowRepoNotFoundOnServer(bool enabled);
+    bool allowRepoNotFoundOnServer() const { return allow_repo_not_found_on_server_; };
+
+    void setHttpSyncCertVerifyDisabled(bool disabled);
+    bool httpSyncCertVerifyDisabled() const { return verify_http_sync_cert_disabled_; };
+
+    QString getComputerName();
+    void setComputerName(const QString& computerName);
+
+    bool isEnableSyncingWithExistingFolder() const;
+    void setEnableSyncingWithExistingFolder(bool enabled);
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+    QString getLastShibUrl();
+    void setLastShibUrl(const QString& url);
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+    bool getFinderSyncExtension() const;
+    bool getFinderSyncExtensionAvailable() const;
+    void setFinderSyncExtension(bool enabled);
+#endif // HAVE_FINDER_SYNC_SUPPORT
+
+#ifdef Q_OS_WIN32
+    void setShellExtensionEnabled(bool enabled);
+    bool shellExtensionEnabled() const { return shell_ext_enabled_; }
+#endif // HAVE_FINDER_SYNC_SUPPORT
+
+public:
+
+    // Remove all settings from system when uninstall
+    static void removeAllSettings();
+    // Write the system proxy information, to be read by seaf-daemon.
+    void writeSystemProxyInfo(const QUrl& url, const QString& file_path);
+
+signals:
+    void autoSyncChanged(bool auto_sync);
+
+private slots:
+    void checkSystemProxy();
+    void onSystemProxyPolled(const QNetworkProxy& proxy);
+
+private:
+    Q_DISABLE_COPY(SettingsManager)
+
+    void loadProxySettings();
+    void writeProxySettingsToDaemon(const SeafileProxy& proxy);
+    void writeProxyDetailsToDaemon(const SeafileProxy& proxy);
+
+    void applyProxySettings();
+
+    bool auto_sync_;
+    bool bubbleNotifycation_;
+    bool autoStart_;
+    bool allow_invalid_worktree_;
+    bool allow_repo_not_found_on_server_;
+    bool sync_extra_temp_file_;
+    unsigned int maxDownloadRatio_;
+    unsigned int maxUploadRatio_;
+    bool verify_http_sync_cert_disabled_;
+    bool shell_ext_enabled_;
+
+    // proxy settings
+    SeafileProxy current_proxy_;
+    QNetworkProxy last_system_proxy_;
+
+    QTimer *check_system_proxy_timer_;
+};
+
+
+// Use to periodically reading the current system proxy.
+class SystemProxyPoller : public QObject, public QRunnable {
+    Q_OBJECT
+public:
+    SystemProxyPoller(const QUrl& url);
+    void run();
+
+signals:
+    void systemProxyPolled(const QNetworkProxy& proxy);
+
+private:
+    QUrl url_;
+};
+
+#endif // SEAFILE_CLIENT_SETTINGS_MANAGER_H
diff --git a/src/shib/shib-helper.h b/src/shib/shib-helper.h
new file mode 100644 (file)
index 0000000..1e73d85
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef SEAFILE_CLIENT_SHIB_HELPER_H
+#define SEAFILE_CLIENT_SHIB_HELPER_H
+
+#include <QWebEnginePage>
+
+class QWebEngineCertificateError;
+class SeafileQWebEnginePage : public QWebEnginePage
+{
+    Q_OBJECT
+public:
+    SeafileQWebEnginePage(QObject *parent = 0);
+
+protected:
+    bool certificateError(
+        const QWebEngineCertificateError &certificateError);
+};
+
+#endif /* SEAFILE_CLIENT_SHIB_HELPER_H */
diff --git a/src/shib/shib-login-dialog.cpp b/src/shib/shib-login-dialog.cpp
new file mode 100644 (file)
index 0000000..5c02790
--- /dev/null
@@ -0,0 +1,187 @@
+#include <QtGui>
+#if defined(SEAFILE_USE_WEBKIT)
+  #include <QWebView>
+#else
+  #include <QWebEngineView>
+  #include <QWebEnginePage>
+  #include <QWebEngineProfile>
+  #include <QWebEngineCookieStore>
+  #include "shib-helper.h"
+#endif
+#include <QVBoxLayout>
+#include <QList>
+#include <QLineEdit>
+#include <QSslError>
+#include <QNetworkReply>
+#include <QNetworkCookie>
+
+#include "seafile-applet.h"
+#include "utils/utils.h"
+#include "utils/api-utils.h"
+#include "account-mgr.h"
+#include "network-mgr.h"
+
+#include "shib-login-dialog.h"
+
+namespace {
+
+const char *kSeahubShibCookieName = "seahub_auth";
+
+} // namespace
+
+ShibLoginDialog::ShibLoginDialog(const QUrl& url,
+                                 const QString& computer_name,
+                                 QWidget *parent)
+    : QDialog(parent),
+      url_(url),
+      cookie_seen_(false)
+{
+    setWindowTitle(tr("Login with Shibboleth"));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    QVBoxLayout *vlayout = new QVBoxLayout();
+    setLayout(vlayout);
+
+    address_text_ = new QLineEdit;
+    address_text_->setObjectName("addressText");
+    address_text_->setText(url.toString());
+    address_text_->setReadOnly(true);
+
+    vlayout->addWidget(address_text_);
+
+#if defined(SEAFILE_USE_WEBKIT)
+    webview_ = new QWebView;
+    CustomCookieJar *jar = new CustomCookieJar(this);
+    QNetworkAccessManager *mgr = webview_->page()->networkAccessManager();
+    NetworkManager::instance()->addWatch(mgr);
+    mgr->setCookieJar(jar);
+
+    connect(mgr, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)),
+            this, SLOT(sslErrorHandler(QNetworkReply*, const QList<QSslError>&)));
+
+    connect(jar, SIGNAL(newCookieCreated(const QUrl&, const QNetworkCookie&)),
+            this, SLOT(onNewCookieCreated(const QUrl&, const QNetworkCookie&)));
+#else
+    webview_ = new QWebEngineView;
+    webview_->setPage(new SeafileQWebEnginePage(this));
+    QWebEngineCookieStore *jar = webview_->page()->profile()->cookieStore();
+    connect(jar, SIGNAL(cookieAdded(const QNetworkCookie&)),
+            this, SLOT(onWebEngineCookieAdded(const QNetworkCookie&)));
+#endif
+
+    QUrl shib_login_url(url_);
+    QString path = shib_login_url.path();
+    if (!path.endsWith("/")) {
+        path += "/";
+    }
+    path += "shib-login";
+    shib_login_url.setPath(path);
+
+    connect(webview_, SIGNAL(urlChanged(const QUrl&)),
+            this, SLOT(updateAddressBar(const QUrl&)));
+
+    vlayout->addWidget(webview_);
+    webview_->load(::includeQueryParams(
+                       shib_login_url, ::getSeafileLoginParams(computer_name, "shib_")));
+}
+
+
+void ShibLoginDialog::sslErrorHandler(QNetworkReply* reply,
+                                      const QList<QSslError> & ssl_errors)
+{
+    reply->ignoreSslErrors();
+}
+
+void ShibLoginDialog::onNewCookieCreated(const QUrl& url, const QNetworkCookie& cookie)
+{
+    if (cookie_seen_) {
+        return;
+    }
+    QString name = cookie.name();
+    QString value = cookie.value();
+    if (url.host() == url_.host() && name == kSeahubShibCookieName) {
+        Account account = parseAccount(value);
+        if (!account.isValid()) {
+            qWarning("wrong account information from server");
+            return;
+        }
+        cookie_seen_ = true;
+        if (!seafApplet->accountManager()->setCurrentAccount(account)) {
+            seafApplet->warningBox(tr("Failed to save current account"), this);
+            reject();
+        } else {
+            accept();
+        }
+    }
+}
+
+void ShibLoginDialog::updateAddressBar(const QUrl& url)
+{
+    address_text_->setText(url.toString());
+    // Scroll to the left most.
+    address_text_->home(false);
+}
+
+
+/**
+ * The cookie value is like seahub_shib="foo@test.com@bd8cc1138", where
+ * foo@test.com is username and bd8cc1138 is api token"
+ */
+Account ShibLoginDialog::parseAccount(const QString& cookie_value)
+{
+    QString txt = cookie_value;
+    if (txt.startsWith("\"")) {
+        txt = txt.mid(1, txt.length() - 2);
+    }
+    int pos = txt.lastIndexOf("@");
+    QString email = txt.left(pos);
+    QString token = txt.right(txt.length() - pos - 1);
+    if (email.isEmpty() or token.isEmpty()) {
+        return Account();
+    }
+    return Account(url_, email, token, 0, true);
+}
+
+void ShibLoginDialog::onWebEngineCookieAdded(const QNetworkCookie& cookie)
+{
+    // printf("cookie added: %s = %s\n", cookie.name().data(), cookie.value().data());
+    if (cookie.name() == kSeahubShibCookieName) {
+        onNewCookieCreated(url_, cookie);
+    }
+}
+
+
+CustomCookieJar::CustomCookieJar(QObject *parent)
+    : QNetworkCookieJar(parent)
+{
+}
+
+bool CustomCookieJar::setCookiesFromUrl(const QList<QNetworkCookie>& cookies, const QUrl& url)
+{
+  if (QNetworkCookieJar::setCookiesFromUrl(cookies, url)) {
+      foreach (const QNetworkCookie& cookie, cookies) {
+          emit newCookieCreated(url, cookie);
+      }
+    return true;
+  }
+
+  return false;
+}
+
+#if !defined(SEAFILE_USE_WEBKIT)
+// We create an off-the-record QWebEngineProfile here, because we don't want the
+// cookie to be persisted (the seahub_auth cookie should be cleared each time
+// the shib login dialog is called)
+SeafileQWebEnginePage::SeafileQWebEnginePage(QObject *parent)
+    : QWebEnginePage(new QWebEngineProfile(parent), parent)
+{
+}
+
+bool SeafileQWebEnginePage::certificateError(
+    const QWebEngineCertificateError &certificateError)
+{
+    return true;
+}
+
+#endif
diff --git a/src/shib/shib-login-dialog.h b/src/shib/shib-login-dialog.h
new file mode 100644 (file)
index 0000000..6e0726c
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef SEAFILE_CLIENT_SHIB_LOGIN_DIALOG_H
+#define SEAFILE_CLIENT_SHIB_LOGIN_DIALOG_H
+
+#include <QDialog>
+#include <QUrl>
+#include <QNetworkCookieJar>
+
+#include "account.h"
+
+template<typename T> class QList;
+
+#if defined(SEAFILE_USE_WEBKIT)
+class QWebView;
+#else
+class QWebEngineView;
+#endif
+
+class QSslError;
+class QNetworkReply;
+class QLineEdit;
+
+/**
+ * Login with Shibboleth SSO.
+ *
+ * This dialog use a webview to let the user login seahub configured with
+ * Shibboleth SSO auth. When the login succeeded, seahub would set the
+ * username and api token in the cookie.
+ */
+class ShibLoginDialog : public QDialog {
+    Q_OBJECT
+public:
+    ShibLoginDialog(const QUrl& url,
+                    const QString& computer_name,
+                    QWidget *parent=0);
+
+private slots:
+    void sslErrorHandler(QNetworkReply* reply, const QList<QSslError> & ssl_errors);
+    void onNewCookieCreated(const QUrl& url, const QNetworkCookie& cookie);
+    void onWebEngineCookieAdded(const QNetworkCookie& cookie);
+    void updateAddressBar(const QUrl& url);
+
+private:
+    Account parseAccount(const QString& txt);
+
+#if defined(SEAFILE_USE_WEBKIT)
+    QWebView *webview_;
+#else
+    QWebEngineView *webview_;
+#endif
+    QUrl url_;
+    QLineEdit *address_text_;
+    bool cookie_seen_;
+};
+
+
+/**
+ * Wraps the standard Qt cookie jar to emit a signal when new cookies created.
+ */
+class CustomCookieJar : public QNetworkCookieJar
+{
+    Q_OBJECT
+public:
+    explicit CustomCookieJar(QObject *parent = 0);
+    bool setCookiesFromUrl(const QList<QNetworkCookie>& cookies, const QUrl& url);
+
+signals:
+    void newCookieCreated(const QUrl& url, const QNetworkCookie& cookie);
+};
+
+#endif /* SEAFILE_CLIENT_SHIB_LOGIN_DIALOG_H */
diff --git a/src/traynotificationmanager.cpp b/src/traynotificationmanager.cpp
new file mode 100644 (file)
index 0000000..1d40e65
--- /dev/null
@@ -0,0 +1,97 @@
+#include "traynotificationmanager.h"
+
+TrayNotificationManager::TrayNotificationManager(QObject *parent)
+  : notificationWidgets(new QList<TrayNotificationWidget*>()), QObject(parent)
+{
+    QDesktopWidget* desktopWidget = QApplication::desktop();
+    QRect clientRect = desktopWidget->availableGeometry();
+    m_maxTrayNotificationWidgets = 4;
+    m_width = 320;
+    m_height = 150;
+    m_onScreenCount = 0;
+#if defined(Q_OS_MAC)
+    m_startX = clientRect.width() - m_width;
+    m_startY = 10;
+    m_up = false;
+#endif
+
+#if defined(Q_OS_LINUX)
+    m_startX = clientRect.width() - m_width;
+    m_startY = 10;
+    m_up = false;
+#endif
+
+#if defined(Q_OS_WIN32)
+    m_startX = clientRect.width() - m_width;
+    m_startY = clientRect.height() - m_height;
+    m_up = true;
+#endif
+
+    m_deltaX = 0;
+    m_deltaY = 0;
+}
+
+TrayNotificationManager::~TrayNotificationManager()
+{
+    // call delete and remove all remaining widgets in notificationWidgets
+    clear();
+
+    // then delete qlist notificationWidgets
+    delete notificationWidgets;
+}
+
+void TrayNotificationManager::setMaxTrayNotificationWidgets(int max)
+{
+    this->m_maxTrayNotificationWidgets = max;
+}
+
+void TrayNotificationManager::append(TrayNotificationWidget* widget)
+{
+    connect(widget, SIGNAL(deleted()), this, SLOT(removeWidget()));
+    if (notificationWidgets->count() < m_maxTrayNotificationWidgets)
+    {
+        if (!notificationWidgets->empty())
+        {
+            if(m_up)
+                m_deltaY += -100;
+            else
+                m_deltaY += 100;
+        } else
+        {
+            m_deltaY = 0;
+        }
+    }
+    else
+    {
+        m_deltaY = 0;
+    }
+
+    widget->setGeometry(m_startX + m_deltaX, m_startY + m_deltaY, widget->size().width(), widget->size().height());
+    notificationWidgets->append(widget);
+}
+
+void TrayNotificationManager::removeWidget()
+{
+    TrayNotificationWidget *widget = qobject_cast<TrayNotificationWidget*>(sender());
+
+    if (widget == NULL)
+    {
+        return;
+    }
+
+    int i = notificationWidgets->indexOf(widget);
+
+    if (i != -1)
+    {
+        notificationWidgets->takeAt(i)->deleteLater();
+    }
+}
+
+void TrayNotificationManager::clear()
+{
+    // call operator delete on all items in list notificationWidgets
+    qDeleteAll(*notificationWidgets);
+
+    // remove all items from it since qDeleteAll don't do it for us
+    notificationWidgets->clear();
+}
diff --git a/src/traynotificationmanager.h b/src/traynotificationmanager.h
new file mode 100644 (file)
index 0000000..ee930f3
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef TRAYNOTIFICATIONMANAGER_H
+#define TRAYNOTIFICATIONMANAGER_H
+
+#include <QtCore>
+#include "traynotificationwidget.h"
+
+class TrayNotificationManager : public QObject
+{
+    Q_OBJECT
+public:
+    TrayNotificationManager(QObject *parent);
+    ~TrayNotificationManager();
+    void append(TrayNotificationWidget *widget);
+    void clear();
+    void setMaxTrayNotificationWidgets(int max);
+
+private slots:
+    void removeWidget();
+
+private:
+    QList<TrayNotificationWidget*>* notificationWidgets;
+    int m_deltaX;
+    int m_deltaY;
+    int m_startX;
+    int m_startY;
+    int m_width;
+    int m_height;
+    bool m_up;
+    int m_onScreenCount;
+    int m_maxTrayNotificationWidgets;
+};
+
+#endif // TRAYNOTIFICATIONMANAGER_H
diff --git a/src/traynotificationwidget.cpp b/src/traynotificationwidget.cpp
new file mode 100644 (file)
index 0000000..f3f1e90
--- /dev/null
@@ -0,0 +1,79 @@
+#include "traynotificationwidget.h"
+
+TrayNotificationWidget::TrayNotificationWidget(QPixmap pixmapIcon, QString headerText, QString messageText) : QWidget(0)
+{
+    setWindowFlags(
+        #if defined(Q_OS_MAC)
+            Qt::SubWindow | // This type flag is the second point
+        #else
+            Qt::Tool |
+        #endif
+            Qt::FramelessWindowHint |
+            Qt::WindowSystemMenuHint |
+            Qt::WindowStaysOnTopHint
+        );
+    setAttribute(Qt::WA_NoSystemBackground, true);
+    // set the parent widget's background to translucent
+    setAttribute(Qt::WA_TranslucentBackground, true);
+
+    //setAttribute(Qt::WA_ShowWithoutActivating, true);
+    setFixedWidth(310);
+    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+    // create a display widget for displaying child widgets
+    QWidget* displayWidget = new QWidget;
+    displayWidget->setStyleSheet(".QWidget { background-color: rgba(0, 0, 0, 75%); border-width: 1px; border-style: solid; border-radius: 10px; border-color: #555555; } .QWidget:hover { background-color: rgba(68, 68, 68, 75%); border-width: 2px; border-style: solid; border-radius: 10px; border-color: #ffffff; }");
+    displayWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+
+    QLabel* icon = new QLabel;
+    icon->setPixmap(pixmapIcon);
+    icon->setMaximumSize(32, 32);
+
+    QLabel* header = new QLabel;
+    header->setStyleSheet("QLabel { color: #ffffff; font-weight: bold; font-size: 12px; }");
+    header->setText(headerText);
+    header->setFixedWidth(200);
+    header->setWordWrap(true);
+    header->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+
+    QTextEdit *message = new QTextEdit;
+    message->setReadOnly(true);
+    message->setFrameStyle(QFrame::NoFrame);
+    message->setLineWrapMode(QTextEdit::WidgetWidth);
+    message->setWordWrapMode(QTextOption::WrapAnywhere);
+
+    QPalette pal = palette();
+    pal.setColor(QPalette::Base, Qt::transparent);
+    message->setPalette(pal);
+    message->setStyleSheet("QTextEdit { color: #ffffff; font-size: 10px; }");
+    message->setText(messageText);
+    message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+    QVBoxLayout* vl = new QVBoxLayout;
+    vl->addWidget(header);
+    vl->addWidget(message);
+
+    QHBoxLayout* displayMainLayout = new QHBoxLayout;
+    displayMainLayout->addWidget(icon);
+    displayMainLayout->addLayout(vl);
+
+    displayWidget->setLayout(displayMainLayout);
+
+    QHBoxLayout* containerLayout = new QHBoxLayout;
+    containerLayout->addWidget(displayWidget);
+    setLayout(containerLayout);
+
+    show();
+    resize(this->size().width(), (int)((message->document()->size().height() + header->height()) +70));
+
+    timeout = new QTimer(this);
+    connect(timeout, SIGNAL(timeout()), this, SLOT(fadeOut()));
+    timeout->start(3000);
+}
+
+void TrayNotificationWidget::fadeOut()
+{
+    timeout->stop();
+
+    this->hide();
+    emit deleted();
+}
diff --git a/src/traynotificationwidget.h b/src/traynotificationwidget.h
new file mode 100644 (file)
index 0000000..a7feb27
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef TRAYNOTIFICATIONWIDGET_H
+#define TRAYNOTIFICATIONWIDGET_H
+
+#include <QWidget>
+
+#include <QtGlobal>
+
+#include <QtWidgets>
+
+class TrayNotificationWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    explicit TrayNotificationWidget(QPixmap pixmapIcon, QString headerText, QString messageText);
+
+private:
+    QTimer* timeout;
+signals:
+    void deleted();
+
+private slots:
+    void fadeOut();
+};
+
+#endif // TRAYNOTIFICATIONWIDGET_H
diff --git a/src/ui/about-dialog.cpp b/src/ui/about-dialog.cpp
new file mode 100644 (file)
index 0000000..e85df39
--- /dev/null
@@ -0,0 +1,52 @@
+#include <QtWidgets>
+
+#include "seafile-applet.h"
+#include "utils/utils.h"
+
+#include "about-dialog.h"
+
+#ifdef HAVE_SPARKLE_SUPPORT
+#include "auto-update-service.h"
+#endif
+
+namespace {
+
+} // namespace
+
+AboutDialog::AboutDialog(QWidget *parent)
+    : QDialog(parent)
+{
+    setupUi(this);
+    setWindowTitle(tr("About %1").arg(getBrand()));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) |
+                   Qt::WindowStaysOnTopHint);
+
+    version_text_ = tr("<h2>%1 Client %2</h2>")
+                       .arg(getBrand())
+                      .arg(STRINGIZE(SEAFILE_CLIENT_VERSION))
+#ifdef SEAFILE_CLIENT_REVISION
+                       .append(tr("<h5> REV %1 </h5>"))
+                       .arg(STRINGIZE(SEAFILE_CLIENT_REVISION))
+#endif
+                      ;
+    mVersionText->setText(version_text_);
+
+    connect(mOKBtn, SIGNAL(clicked()), this, SLOT(close()));
+
+    mCheckUpdateBtn->setVisible(false);
+#ifdef HAVE_SPARKLE_SUPPORT
+    if (AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
+        mCheckUpdateBtn->setVisible(true);
+        connect(mCheckUpdateBtn, SIGNAL(clicked()), this, SLOT(checkUpdate()));
+    }
+#endif
+}
+
+#ifdef HAVE_SPARKLE_SUPPORT
+void AboutDialog::checkUpdate()
+{
+    AutoUpdateService::instance()->checkUpdate();
+    close();
+}
+#endif
diff --git a/src/ui/about-dialog.h b/src/ui/about-dialog.h
new file mode 100644 (file)
index 0000000..110e557
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef SEAFILE_CLIENT_ABOUT_DIALOG_H
+#define SEAFILE_CLIENT_ABOUT_DIALOG_H
+
+#include <QDialog>
+#include "ui_about-dialog.h"
+
+class AutoUpdateService;
+
+class AboutDialog : public QDialog,
+                    public Ui::AboutDialog
+{
+    Q_OBJECT
+public:
+    AboutDialog(QWidget *parent=0);
+
+#ifdef HAVE_SPARKLE_SUPPORT
+private slots:
+    void checkUpdate();
+#endif
+
+private:
+    Q_DISABLE_COPY(AboutDialog)
+
+    QString version_text_;
+};
+
+#endif // SEAFILE_CLIENT_ABOUT_DIALOG_H
diff --git a/src/ui/account-settings-dialog.cpp b/src/ui/account-settings-dialog.cpp
new file mode 100644 (file)
index 0000000..6c09cb4
--- /dev/null
@@ -0,0 +1,98 @@
+#include <QtGui>
+
+#include "settings-mgr.h"
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "account-settings-dialog.h"
+
+namespace {
+
+} // namespace
+
+AccountSettingsDialog::AccountSettingsDialog(const Account& account, QWidget *parent)
+    : QDialog(parent),
+      account_(account)
+{
+    setupUi(this);
+    setWindowTitle(tr("Account Settings"));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    mServerAddr->setText(account_.serverUrl.toString());
+    mUsername->setText(account_.username);
+    mUsername->setEnabled(false);
+
+    #if defined(Q_OS_MAC)
+    layout()->setContentsMargins(9, 9, 9, 9);
+    layout()->setSpacing(6);
+    formLayout->setSpacing(6);
+    formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
+    formLayout->setLabelAlignment(Qt::AlignLeft);
+    formLayout->setFormAlignment(Qt::AlignLeft);
+    horizontalLayout->setSpacing(6);
+    #endif
+
+    connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onSubmitBtnClicked()));
+
+    // const QRect screen = QApplication::desktop()->screenGeometry();
+    // move(screen.center() - this->rect().center());
+}
+
+void AccountSettingsDialog::showWarning(const QString& msg)
+{
+    seafApplet->warningBox(msg, this);
+}
+
+bool AccountSettingsDialog::validateInputs()
+{
+    QString server_addr = mServerAddr->text().trimmed();
+    QUrl url;
+
+    if (server_addr.size() == 0) {
+        showWarning(tr("Please enter the server address"));
+        return false;
+    } else {
+        if (!server_addr.startsWith("http://") && !server_addr.startsWith("https://")) {
+            showWarning(tr("%1 is not a valid server address").arg(server_addr));
+            return false;
+        }
+
+        url = QUrl(server_addr, QUrl::StrictMode);
+        if (!url.isValid()) {
+            showWarning(tr("%1 is not a valid server address").arg(server_addr));
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void AccountSettingsDialog::onSubmitBtnClicked()
+{
+    if (!validateInputs()) {
+        return;
+    }
+
+    QString url = mServerAddr->text().trimmed();
+    if (url != account_.serverUrl.toString()) {
+        Account new_account(account_);
+        new_account.serverUrl = url;
+        if (seafApplet->accountManager()->replaceAccount(account_,
+            new_account) < 0) {
+            showWarning(tr("Failed to save account information"));
+            return;
+        }
+        QString error;
+        QUrl new_server_url = new_account.serverUrl;
+        new_server_url.setPath("/");
+        if (seafApplet->rpcClient()->updateReposServerHost(account_.serverUrl.host(),
+            new_account.serverUrl.host(), new_server_url.toString(), &error) < 0) {
+            showWarning(tr("Failed to save the changes: %1").arg(error));
+            return;
+        }
+    }
+
+    seafApplet->messageBox(tr("Successfully updated current account information"), this);
+    accept();
+}
diff --git a/src/ui/account-settings-dialog.h b/src/ui/account-settings-dialog.h
new file mode 100644 (file)
index 0000000..4ed277c
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef SEAFILE_CLIENT_ACCOUNT_SETTINGS_H
+#define SEAFILE_CLIENT_ACCOUNT_SETTINGS_H
+
+#include <QDialog>
+#include "ui_account-settings-dialog.h"
+
+#include <QUrl>
+#include <QString>
+
+#include "account.h"
+
+class AccountSettingsDialog : public QDialog,
+                              public Ui::AccountSettingsDialog
+{
+    Q_OBJECT
+public:
+    AccountSettingsDialog(const Account& account, QWidget *parent=0);
+
+private slots:
+    void onSubmitBtnClicked();
+
+private:
+    Q_DISABLE_COPY(AccountSettingsDialog);
+    bool validateInputs();
+    void showWarning(const QString& msg);
+
+    Account account_;
+};
+
+#endif // SEAFILE_CLIENT_ACCOUNT_SETTINGS_H
diff --git a/src/ui/account-view.cpp b/src/ui/account-view.cpp
new file mode 100644 (file)
index 0000000..8f13cf9
--- /dev/null
@@ -0,0 +1,365 @@
+#include <QMenu>
+#include <QAction>
+#include <QToolButton>
+#include <QScopedPointer>
+#include <QPainter>
+#include <QStringList>
+#include <QDesktopServices>
+#include <QMouseEvent>
+#include <QUrl>
+#include <QUrlQuery>
+#include <QThreadPool>
+
+#include "account.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "login-dialog.h"
+#include "settings-mgr.h"
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+#include "shib/shib-login-dialog.h"
+#endif // HAVE_SHIBBOLETH_SUPPORT
+#include "account-settings-dialog.h"
+#include "rpc/rpc-client.h"
+#include "main-window.h"
+#include "init-vdrive-dialog.h"
+#include "auto-login-service.h"
+#include "avatar-service.h"
+#include "utils/paint-utils.h"
+#include "filebrowser/file-browser-manager.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "filebrowser/auto-update-mgr.h"
+#include "repo-service.h"
+
+#include "account-view.h"
+namespace {
+
+} // namespace
+
+AccountView::AccountView(QWidget *parent)
+    : QWidget(parent)
+{
+    setupUi(this);
+
+    // Init account drop down menu
+    account_menu_ = new QMenu;
+    mAccountBtn->setMenu(account_menu_);
+    mAccountBtn->setPopupMode(QToolButton::InstantPopup);
+    mAccountBtn->setFixedSize(QSize(AvatarService::kAvatarSize, AvatarService::kAvatarSize));
+
+    onAccountChanged();
+
+    connect(AvatarService::instance(), SIGNAL(avatarUpdated(const QString&, const QImage&)),
+            this, SLOT(updateAvatar()));
+
+    mAccountBtn->setCursor(Qt::PointingHandCursor);
+    mAccountBtn->installEventFilter(this);
+    account_menu_->installEventFilter(this);
+
+    connect(seafApplet->accountManager(), SIGNAL(requireAddAccount()),
+            this, SLOT(showAddAccountDialog()));
+    connect(mServerAddr, SIGNAL(linkActivated(const QString&)),
+            this, SLOT(visitServerInBrowser(const QString&)));
+
+    // Must get the pixmap from QIcon because QIcon would load the 2x version
+    // automatically.
+    mRefreshLabel->setPixmap(QIcon(":/images/toolbar/refresh-new.png").pixmap(20));
+    mRefreshLabel->installEventFilter(this);
+}
+
+void AccountView::showAddAccountDialog()
+{
+    LoginDialog dialog(this);
+    // Show InitVirtualDriveDialog for the first account added
+    AccountManager *account_mgr = seafApplet->accountManager();
+    if (dialog.exec() == QDialog::Accepted
+        && account_mgr->accounts().size() == 1) {
+
+        InitVirtualDriveDialog dialog(account_mgr->currentAccount(), seafApplet->mainWindow());
+#if defined(Q_OS_WIN32)
+        dialog.exec();
+#endif
+    }
+}
+
+void AccountView::deleteAccount()
+{
+    QAction *action = qobject_cast<QAction*>(sender());
+    if (!action)
+        return;
+    Account account = qvariant_cast<Account>(action->data());
+
+    // QString question = tr("Are you sure to remove account from \"%1\"?<br>"
+    //                       "<b>Warning: All libraries of this account would be unsynced!</b>").arg(account.serverUrl.toString());
+
+    QString question = tr("Are you sure you want to remove account %1?<br><br>"
+                          "The account will be removed locally. All syncing "
+                          "configuration will be removed too. The account at "
+                          "the server will not be affected.")
+                           .arg(account.username);
+
+    if (seafApplet->yesOrNoBox(question, this, false)) {
+        FileBrowserManager::getInstance()->closeAllDialogByAccount(account);
+        QString error, server_addr = account.serverUrl.host();
+        if (seafApplet->rpcClient()->unsyncReposByAccount(server_addr,
+                                                          account.username,
+                                                          &error) < 0) {
+
+            seafApplet->warningBox(
+                tr("Failed to unsync libraries of this account: %1").arg(error),
+                this);
+        }
+
+        seafApplet->accountManager()->removeAccount(account);
+    }
+}
+
+void AccountView::editAccountSettings()
+{
+    QAction *action = qobject_cast<QAction*>(sender());
+    if (!action)
+        return;
+    Account account = qvariant_cast<Account>(action->data());
+
+    AccountSettingsDialog dialog(account, this);
+
+    dialog.exec();
+}
+
+void AccountView::updateAccountInfoDisplay()
+{
+    if (seafApplet->accountManager()->hasAccount()) {
+        const Account account = seafApplet->accountManager()->currentAccount();
+        if (!account.accountInfo.name.isEmpty()) {
+            mEmail->setText(account.accountInfo.name);
+        } else {
+            mEmail->setText(account.username);
+        }
+        // mServerAddr->setOpenExternalLinks(true);
+        mServerAddr->setToolTip(tr("click to open the website"));
+
+        QString host = account.serverUrl.host();
+        QString href = account.serverUrl.toString();
+        QString text = QString("<a style="
+                               "\"color:#A4A4A4; text-decoration: none;\" "
+                               "href=\"%1\">%2</a>").arg(href).arg(host);
+
+        mServerAddr->setText(account.isPro() ? QString("%1 <small>%2<small>").arg(text).arg(tr("pro version")) : text);
+    } else {
+        mEmail->setText(tr("No account"));
+        mServerAddr->setText(QString());
+    }
+
+    updateAvatar();
+}
+
+/**
+ * Update the account menu when accounts changed
+ */
+void AccountView::onAccountChanged()
+{
+    const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+
+    // Remove all menu items
+    account_menu_->clear();
+
+    if (!accounts.empty()) {
+        for (size_t i = 0, n = accounts.size(); i < n; i++) {
+            const Account &account = accounts[i];
+            QString text_name = account.accountInfo.name.isEmpty() ?
+                        account.username : account.accountInfo.name;
+            QString text = text_name + " (" + account.serverUrl.host() + ")";
+            if (!account.isValid()) {
+                text += ", " + tr("not logged in");
+            }
+            QMenu *submenu = new QMenu(text, account_menu_);
+            if (i == 0) {
+                submenu->setIcon(QIcon(":/images/account-checked.png"));
+            } else {
+                submenu->setIcon(QIcon(":/images/account-else.png"));
+            }
+
+            QAction *submenu_action = submenu->menuAction();
+            submenu_action->setData(QVariant::fromValue(account));
+            connect(submenu_action, SIGNAL(triggered()), this, SLOT(onAccountItemClicked()));
+
+            QAction *action = new QAction(tr("Choose"), submenu);
+            action->setIcon(QIcon(":/images/account-checked.png"));
+            action->setIconVisibleInMenu(true);
+            action->setData(QVariant::fromValue(account));
+            connect(action, SIGNAL(triggered()), this, SLOT(onAccountItemClicked()));
+
+            submenu->addAction(action);
+            submenu->setDefaultAction(action);
+
+            QAction *account_settings_action = new QAction(tr("Account settings"), this);
+            account_settings_action->setIcon(QIcon(":/images/account-settings.png"));
+            account_settings_action->setIconVisibleInMenu(true);
+            account_settings_action->setData(QVariant::fromValue(account));
+            connect(account_settings_action, SIGNAL(triggered()), this, SLOT(editAccountSettings()));
+            submenu->addAction(account_settings_action);
+
+            QAction *toggle_action = new QAction(this);
+            toggle_action->setIcon(QIcon(":/images/logout.png"));
+            toggle_action->setIconVisibleInMenu(true);
+            toggle_action->setData(QVariant::fromValue(account));
+            connect(toggle_action, SIGNAL(triggered()), this, SLOT(toggleAccount()));
+            if (account.isValid())
+                toggle_action->setText(tr("Logout"));
+            else
+                toggle_action->setText(tr("Login"));
+            submenu->addAction(toggle_action);
+
+            QAction *delete_account_action = new QAction(tr("Delete"), this);
+            delete_account_action->setIcon(QIcon(":/images/delete-account.png"));
+            delete_account_action->setIconVisibleInMenu(true);
+            delete_account_action->setData(QVariant::fromValue(account));
+            connect(delete_account_action, SIGNAL(triggered()), this, SLOT(deleteAccount()));
+            submenu->addAction(delete_account_action);
+
+            account_menu_->addMenu(submenu);
+        }
+
+        account_menu_->addSeparator();
+    }
+
+    add_account_action_ = new QAction(tr("Add an account"), this);
+    add_account_action_->setIcon(QIcon(":/images/add-account.png"));
+    add_account_action_->setIconVisibleInMenu(true);
+    connect(add_account_action_, SIGNAL(triggered()), this, SLOT(showAddAccountDialog()));
+    account_menu_->addAction(add_account_action_);
+
+    updateAccountInfoDisplay();
+}
+
+QAction* AccountView::makeAccountAction(const Account& account)
+{
+    QString text = account.username + "(" + account.serverUrl.host() + ")";
+    if (!account.isValid()) {
+        text += ", " + tr("not logged in");
+    }
+    QAction *action = new QAction(text, account_menu_);
+    action->setData(QVariant::fromValue(account));
+    // action->setCheckable(true);
+    // QMenu won't display tooltip for menu item
+    // action->setToolTip(account.serverUrl.host());
+
+    connect(action, SIGNAL(triggered()), this, SLOT(onAccountItemClicked()));
+
+    return action;
+}
+
+// Switch to the clicked account in the account menu
+void AccountView::onAccountItemClicked()
+{
+    QAction *action = (QAction *)(sender());
+    Account account = qvariant_cast<Account>(action->data());
+
+    if (!account.isValid()) {
+        seafApplet->accountManager()->reloginAccount(account);
+    } else {
+        seafApplet->accountManager()->setCurrentAccount(account);
+    }
+}
+
+void AccountView::updateAvatar()
+{
+    mAccountBtn->setIconSize(QSize(AvatarService::kAvatarSize, AvatarService::kAvatarSize));
+    const Account account = seafApplet->accountManager()->currentAccount();
+    if (!account.isValid())  {
+        mAccountBtn->setIcon(QIcon(":/images/account.png"));
+        return;
+    }
+
+    AvatarService *service = AvatarService::instance();
+    QIcon avatar = QPixmap::fromImage(service->getAvatar(account.username));
+    mAccountBtn->setIcon(QIcon(avatar));
+}
+
+bool AccountView::eventFilter(QObject *obj, QEvent *event)
+{
+    if (obj == account_menu_ && event->type() == QEvent::MouseButtonRelease) {
+        QMouseEvent *ev = (QMouseEvent*)event;
+        QAction *action = account_menu_->actionAt(ev->pos());
+        if (action) {
+            action->trigger();
+        }
+    }
+    if (obj == mAccountBtn && event->type() == QEvent::Paint) {
+        QRect rect(0, 0, AvatarService::kAvatarSize, AvatarService::kAvatarSize);
+        QPainter painter(mAccountBtn);
+        painter.setRenderHint(QPainter::Antialiasing);
+        painter.setRenderHint(QPainter::HighQualityAntialiasing);
+
+        // get the device pixel radio from current painter device
+        double scale_factor = globalDevicePixelRatio();
+
+        QPixmap image(mAccountBtn->icon().pixmap(rect.size()).scaled(scale_factor * rect.size()));
+        QRect actualRect(QPoint(0, 0),
+                         QSize(AvatarService::kAvatarSize * scale_factor,
+                               AvatarService::kAvatarSize * scale_factor));
+
+        QImage masked_image(actualRect.size(),
+                            QImage::Format_ARGB32_Premultiplied);
+        masked_image.fill(Qt::transparent);
+        QPainter mask_painter;
+        mask_painter.begin(&masked_image);
+        mask_painter.setRenderHint(QPainter::Antialiasing);
+        mask_painter.setRenderHint(QPainter::HighQualityAntialiasing);
+        mask_painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+        mask_painter.setPen(Qt::NoPen);
+        mask_painter.setBrush(Qt::white);
+        mask_painter.drawEllipse(actualRect);
+        mask_painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+        mask_painter.drawPixmap(actualRect, image);
+        mask_painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
+        mask_painter.fillRect(actualRect, Qt::transparent);
+        mask_painter.end();
+        masked_image.setDevicePixelRatio(scale_factor);
+
+        painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+        painter.drawImage(QPoint(0,0), masked_image);
+        return true;
+    }
+    if (obj == mRefreshLabel) {
+        if (event->type() == QEvent::MouseButtonPress) {
+            emit refresh();
+            return true;
+        } else if (event->type() == QEvent::Enter) {
+            mRefreshLabel->setPixmap(QIcon(":/images/toolbar/refresh-orange.png").pixmap(20));
+            return true;
+        } else if (event->type() == QEvent::Leave) {
+            mRefreshLabel->setPixmap(QIcon(":/images/toolbar/refresh-new.png").pixmap(20));
+            return true;
+        }
+    }
+    return QObject::eventFilter(obj, event);
+}
+
+/**
+ * Only remove the api token of the account. The accout would still be shown
+ * in the account list.
+ */
+void AccountView::toggleAccount()
+{
+    QAction *action = qobject_cast<QAction*>(sender());
+    if (!action)
+        return;
+    Account account = qvariant_cast<Account>(action->data());
+    if (!account.isValid()) {
+        seafApplet->accountManager()->reloginAccount(account);
+        return;
+    }
+
+    qWarning("Logging out current account %s", account.username.toUtf8().data());
+    AutoUpdateManager::instance()->cleanCachedFile();
+
+    // logout Account
+    FileBrowserManager::getInstance()->closeAllDialogByAccount(account);
+    seafApplet->accountManager()->logoutDevice(account);
+}
+
+void AccountView::visitServerInBrowser(const QString& link)
+{
+    AutoLoginService::instance()->startAutoLogin("/");
+}
diff --git a/src/ui/account-view.h b/src/ui/account-view.h
new file mode 100644 (file)
index 0000000..ce4a772
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef SEAFILE_CLIENT_UI_ACCOUNT_VIEW_H
+#define SEAFILE_CLIENT_UI_ACCOUNT_VIEW_H
+
+#include <QWidget>
+
+#include "utils/singleton.h"
+#include "ui_account-view.h"
+
+class Account;
+class QAction;
+class QMenu;
+class ApiError;
+class QLabel;
+
+/*
+ * The account information area, right below the header
+ */
+class AccountView : public QWidget,
+                    public Ui::AccountView
+{
+    Q_OBJECT
+public:
+    AccountView(QWidget *parent=0);
+
+public slots:
+    void onAccountChanged();
+    void showAddAccountDialog();
+    void deleteAccount();
+    void editAccountSettings();
+    void onAccountItemClicked();
+    void updateAccountInfoDisplay();
+
+private slots:
+    void updateAvatar();
+    void toggleAccount();
+    void visitServerInBrowser(const QString& link);
+
+private:
+    Q_DISABLE_COPY(AccountView)
+
+    QAction *makeAccountAction(const Account& account);
+    bool eventFilter(QObject *obj, QEvent *event);
+
+    // Account operations
+    QAction *add_account_action_;
+    QAction *account_settings_action_;
+    QMenu *account_menu_;
+
+signals:
+    void refresh();
+};
+
+#endif // SEAFILE_CLIENT_UI_ACCOUNT_VIEW_H
diff --git a/src/ui/activities-tab.cpp b/src/ui/activities-tab.cpp
new file mode 100644 (file)
index 0000000..bd28221
--- /dev/null
@@ -0,0 +1,190 @@
+#include <cstdio>
+#include <QtGlobal>
+
+#include <QtWidgets>
+#include <QIcon>
+#include <QStackedWidget>
+#include <QModelIndex>
+#include <QLabel>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "events-list-view.h"
+#include "loading-view.h"
+#include "logout-view.h"
+#include "events-service.h"
+#include "avatar-service.h"
+#include "api/api-error.h"
+#include "utils/utils.h"
+
+#include "activities-tab.h"
+
+namespace {
+
+//const int kRefreshInterval = 1000 * 60 * 5; // 5 min
+const char *kLoadingFailedLabelName = "loadingFailedText";
+//const char *kEmptyViewLabelName = "emptyText";
+//const char *kAuthHeader = "Authorization";
+//const char *kActivitiesUrl = "/api2/html/events/";
+
+enum {
+    INDEX_LOADING_VIEW = 0,
+    INDEX_LOADING_FAILED_VIEW,
+    INDEX_LOGOUT_VIEW,
+    INDEX_EVENTS_VIEW,
+};
+
+
+}
+
+
+ActivitiesTab::ActivitiesTab(QWidget *parent)
+    : TabView(parent)
+{
+    createEventsView();
+    createLoadingView();
+    createLoadingFailedView();
+
+    //createLogoutView
+    logout_view_ = new LogoutView;
+    static_cast<LogoutView*>(logout_view_)->setQssStyleForTab();
+
+    mStack->insertWidget(INDEX_LOADING_VIEW, loading_view_);
+    mStack->insertWidget(INDEX_LOADING_FAILED_VIEW, loading_failed_view_);
+    mStack->insertWidget(INDEX_LOGOUT_VIEW, logout_view_);
+    mStack->insertWidget(INDEX_EVENTS_VIEW, events_container_view_);
+
+    connect(EventsService::instance(), SIGNAL(refreshSuccess(const std::vector<SeafEvent>&, bool, bool)),
+            this, SLOT(refreshEvents(const std::vector<SeafEvent>&, bool, bool)));
+    connect(EventsService::instance(), SIGNAL(refreshFailed(const ApiError&)),
+            this, SLOT(refreshFailed(const ApiError&)));
+
+    connect(AvatarService::instance(), SIGNAL(avatarUpdated(const QString&, const QImage&)),
+            events_list_model_, SLOT(onAvatarUpdated(const QString&, const QImage&)));
+
+    refresh();
+}
+
+void ActivitiesTab::showEvent(QShowEvent *event)
+{
+    TabView::showEvent(event);
+    if (mStack->currentIndex() == INDEX_EVENTS_VIEW) {
+        events_list_view_->update();
+    }
+}
+
+void ActivitiesTab::loadMoreEvents()
+{
+    EventsService::instance()->loadMore();
+}
+
+void ActivitiesTab::refreshEvents(const std::vector<SeafEvent>& events,
+                                  bool is_loading_more,
+                                  bool has_more)
+{
+    events_list_model_->removeRow(
+        events_list_model_->loadMoreIndex().row());
+
+    mStack->setCurrentIndex(INDEX_EVENTS_VIEW);
+
+    // XXX: "load more events" for now
+    const QModelIndex first =
+        events_list_model_->updateEvents(events, is_loading_more, has_more);
+    if (first.isValid()) {
+        events_list_view_->scrollTo(first);
+    }
+
+    if (has_more) {
+        load_more_btn_ = new LoadMoreButton;
+        connect(load_more_btn_, SIGNAL(clicked()),
+                this, SLOT(loadMoreEvents()));
+        events_list_view_->setIndexWidget(
+            events_list_model_->loadMoreIndex(), load_more_btn_);
+    }
+}
+
+void ActivitiesTab::refresh()
+{
+    if (!seafApplet->accountManager()->hasAccount() ||
+        !seafApplet->accountManager()->accounts().front().isValid()) {
+        mStack->setCurrentIndex(INDEX_LOGOUT_VIEW);
+        return;
+    }
+    showLoadingView();
+
+    EventsService::instance()->refresh(true);
+}
+
+void ActivitiesTab::createEventsView()
+{
+    events_container_view_ = new QWidget;
+    events_container_view_->setObjectName("EventsContainerView");
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->setContentsMargins(0, 0, 0, 0);
+    layout->setSpacing(0);
+    events_container_view_->setLayout(layout);
+
+    events_list_view_ = new EventsListView;
+    layout->addWidget(events_list_view_);
+
+    events_list_model_ = new EventsListModel;
+    events_list_view_->setModel(events_list_model_);
+}
+
+void ActivitiesTab::createLoadingView()
+{
+    loading_view_ = new LoadingView;
+    static_cast<LoadingView*>(loading_view_)->setQssStyleForTab();
+}
+
+void ActivitiesTab::createLoadingFailedView()
+{
+    loading_failed_view_ = new QWidget(this);
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    loading_failed_view_->setLayout(layout);
+
+    loading_failed_text_ = new QLabel;
+    loading_failed_text_->setObjectName(kLoadingFailedLabelName);
+    loading_failed_text_->setAlignment(Qt::AlignCenter);
+
+    connect(loading_failed_text_, SIGNAL(linkActivated(const QString&)),
+            this, SLOT(refresh()));
+
+    layout->addWidget(loading_failed_text_);
+}
+
+void ActivitiesTab::showLoadingView()
+{
+    mStack->setCurrentIndex(INDEX_LOADING_VIEW);
+}
+
+void ActivitiesTab::refreshFailed(const ApiError& error)
+{
+    QString text;
+    if (error.type() == ApiError::HTTP_ERROR
+        && error.httpErrorCode() == 404) {
+        text = tr("File Activities are only supported in %1 Server Professional Edition.").arg(getBrand());
+    } else {
+        QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("retry"));
+        text = tr("Failed to get actvities information. "
+                  "Please %1").arg(link);
+    }
+
+    loading_failed_text_->setText(text);
+
+    mStack->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+}
+
+void ActivitiesTab::startRefresh()
+{
+    AccountManager *mgr = seafApplet->accountManager();
+    bool has_pro_account = mgr->hasAccount() && mgr->accounts().front().isPro();
+    if (has_pro_account)
+        EventsService::instance()->start();
+}
+
+void ActivitiesTab::stopRefresh()
+{
+    EventsService::instance()->stop();
+}
diff --git a/src/ui/activities-tab.h b/src/ui/activities-tab.h
new file mode 100644 (file)
index 0000000..cbb459d
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef SEAFILE_CLIENT_UI_ACTIVITIES_TAB_H
+#define SEAFILE_CLIENT_UI_ACTIVITIES_TAB_H
+
+#include <vector>
+#include <QList>
+
+#include "tab-view.h"
+
+class QSslError;
+class QUrl;
+class QNetworkRequest;
+class QNetworkReply;
+class LoadMoreButton;
+class QLabel;
+class QShowEvent;
+
+class SeafEvent;
+class Account;
+class ApiError;
+class EventsListView;
+class EventsListModel;
+
+/**
+ * The activities tab
+ */
+class ActivitiesTab : public TabView {
+    Q_OBJECT
+public:
+    explicit ActivitiesTab(QWidget *parent=0);
+
+public slots:
+    void refresh();
+
+protected:
+    void startRefresh();
+    void stopRefresh();
+    virtual void showEvent(QShowEvent *event);
+
+private slots:
+    void refreshEvents(const std::vector<SeafEvent>& events,
+                       bool is_loading_more,
+                       bool has_more);
+    void refreshFailed(const ApiError& error);
+    void loadMoreEvents();
+
+private:
+    void createEventsView();
+    void createLoadingView();
+    void createLoadingFailedView();
+    void showLoadingView();
+    void loadPage(const Account& account);
+
+    QWidget *loading_view_;
+    QWidget *loading_failed_view_;
+    QWidget *logout_view_;
+
+    QWidget *events_container_view_;
+    EventsListView *events_list_view_;
+    EventsListModel *events_list_model_;
+    QWidget *events_loading_view_;
+    LoadMoreButton *load_more_btn_;
+
+    QLabel *loading_failed_text_;
+};
+
+#endif // SEAFILE_CLIENT_UI_ACTIVITIES_TAB_H
diff --git a/src/ui/check-repo-root-perm-dialog.cpp b/src/ui/check-repo-root-perm-dialog.cpp
new file mode 100644 (file)
index 0000000..86beada
--- /dev/null
@@ -0,0 +1,100 @@
+#include <QtGui>
+#include <QTimer>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QProgressBar>
+#include <QPushButton>
+
+#include "filebrowser/seaf-dirent.h"
+#include "filebrowser/data-mgr.h"
+#include "seafile-applet.h"
+
+#include "check-repo-root-perm-dialog.h"
+
+CheckRepoRootDirPermDialog::CheckRepoRootDirPermDialog(const Account &account,
+                                                       const ServerRepo& repo,
+                                                       const QString& local_path,
+                                                       QWidget *parent)
+    : QProgressDialog(parent),
+      account_(account),
+      repo_(repo),
+      local_path_(local_path),
+      has_write_perm_(false)
+{
+    // Here we use the data manager class to fetch the dir instead of doing it
+    // directly, because DataManager class would make use of the shared
+    // in-memory dirents cache.
+    data_mgr_ = seafApplet->dataManager();
+
+    setWindowModality(Qt::WindowModal);
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+    setWindowIcon(QIcon(":/images/seafile.png"));
+
+    QVBoxLayout *layout_ = new QVBoxLayout;
+    progress_bar_ = new QProgressBar;
+    description_label_ = new QLabel;
+
+    layout_->addWidget(description_label_);
+    layout_->addWidget(progress_bar_);
+
+    QHBoxLayout *hlayout_ = new QHBoxLayout;
+    more_details_label_ = new QLabel;
+    more_details_label_->setText(tr("Checking Permission"));
+    QPushButton *cancel_button_ = new QPushButton(tr("Cancel"));
+    QWidget *spacer = new QWidget;
+    spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+    hlayout_->addWidget(more_details_label_);
+    hlayout_->addWidget(spacer);
+    hlayout_->addWidget(cancel_button_);
+    hlayout_->setContentsMargins(-1, 0, -1, 6);
+    layout_->setContentsMargins(-1, 0, -1, 6);
+    layout_->addLayout(hlayout_);
+
+    setLayout(layout_);
+    setLabel(description_label_);
+    setBar(progress_bar_);
+    setCancelButton(cancel_button_);
+
+    data_mgr_notify_ = new DataManagerNotify(repo_.id);
+    connect(data_mgr_notify_, SIGNAL(getDirentsSuccess(bool, const QList<SeafDirent>&)),
+            this, SLOT(onGetDirentsSuccess(bool)));
+    connect(data_mgr_notify_, SIGNAL(getDirentsFailed(const ApiError&)),
+            this, SLOT(onGetDirentsFailed()));
+
+    setValue(minimum());
+    QTimer::singleShot(0, this, SLOT(checkPerm()));
+}
+
+CheckRepoRootDirPermDialog::~CheckRepoRootDirPermDialog()
+{
+    // printf ("destructor called for CheckRepoRootDirPermDialog\n");
+    delete data_mgr_notify_;
+}
+
+void CheckRepoRootDirPermDialog::checkPerm()
+{
+    QList<SeafDirent> dirents;
+    bool readonly;
+    if (data_mgr_->getDirents(repo_.id, "/", &dirents, &readonly)) {
+        onGetDirentsSuccess(readonly);
+        return;
+    }
+
+    data_mgr_->getDirentsFromServer(repo_.id, "/");
+}
+
+void CheckRepoRootDirPermDialog::onGetDirentsSuccess(bool readonly)
+{
+    has_write_perm_ = !readonly;
+    setValue(maximum());
+    accept();
+}
+
+void CheckRepoRootDirPermDialog::onGetDirentsFailed()
+{
+    has_write_perm_ = false;
+    setValue(maximum());
+    accept();
+}
diff --git a/src/ui/check-repo-root-perm-dialog.h b/src/ui/check-repo-root-perm-dialog.h
new file mode 100644 (file)
index 0000000..c2c7f7a
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef SEAFILE_CLIENT_CHECK_REPO_ROOT_PERM_DIALOG_H
+#define SEAFILE_CLIENT_CHECK_REPO_ROOT_PERM_DIALOG_H
+
+#include <QUrl>
+#include <QString>
+#include <QProgressDialog>
+
+#include "api/server-repo.h"
+#include "account.h"
+#include "filebrowser/file-browser-dialog.h"
+
+class ApiError;
+class DataManager;
+class SeafDirent;
+
+// When the user drag'n'drop a file into to a repo and the repo is readonly, we
+// need to check the user's directory-level permission for the repo's root
+// directory.
+//
+// This dialog would be showed to the user when we send the request to the server.
+//
+class CheckRepoRootDirPermDialog : public QProgressDialog
+{
+    Q_OBJECT
+public:
+    CheckRepoRootDirPermDialog(const Account &account,
+                               const ServerRepo& repo,
+                               const QString& local_path,
+                               QWidget *parent = 0);
+    ~CheckRepoRootDirPermDialog();
+
+    QString localPath() const { return local_path_; }
+    ServerRepo repo() const { return repo_; }
+
+    bool hasWritePerm() const { return has_write_perm_; }
+
+private slots:
+    void checkPerm();
+    void onGetDirentsSuccess(bool readonly);
+    void onGetDirentsFailed();
+
+private:
+    Q_DISABLE_COPY(CheckRepoRootDirPermDialog);
+
+    Account account_;
+    ServerRepo repo_;
+    QString local_path_;
+
+    bool has_write_perm_;
+
+    QLabel *description_label_;
+    QLabel *more_details_label_;
+    QProgressBar *progress_bar_;
+    DataManager *data_mgr_;
+    DataManagerNotify *data_mgr_notify_;
+};
+
+#endif // SEAFILE_CLIENT_CHECK_REPO_ROOT_PERM_DIALOG_H
diff --git a/src/ui/clone-tasks-dialog.cpp b/src/ui/clone-tasks-dialog.cpp
new file mode 100644 (file)
index 0000000..e63aa08
--- /dev/null
@@ -0,0 +1,86 @@
+#include <QtGlobal>
+
+#include <QtWidgets>
+#include <QTableView>
+#include <QTimer>
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "rpc/clone-task.h"
+#include "clone-tasks-table-model.h"
+#include "clone-tasks-table-view.h"
+#include "clone-tasks-dialog.h"
+
+namespace {
+
+//const int kUpdateTasksInterval = 1000;
+
+enum {
+    INDEX_EMPTY_VIEW = 0,
+    INDEX_TASKS_VIEW
+};
+
+} // namespace
+
+
+CloneTasksDialog::CloneTasksDialog(QWidget *parent)
+    : QDialog(parent)
+{
+    setupUi(this);
+
+    setWindowTitle(tr("Download tasks"));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    setMinimumSize(QSize(600, 300));
+
+    createEmptyView();
+
+    table_ = new CloneTasksTableView;
+    model_ = new CloneTasksTableModel(this);
+    table_->setModel(model_);
+
+    stack_ = new QStackedWidget;
+    stack_->insertWidget(INDEX_EMPTY_VIEW, empty_view_);
+    stack_->insertWidget(INDEX_TASKS_VIEW, table_);
+
+    QVBoxLayout *vlayout = (QVBoxLayout *)layout();
+    vlayout->insertWidget(0, stack_);
+
+    mClearBtn->setToolTip(tr("remove all successful tasks"));
+    connect(mClearBtn, SIGNAL(clicked()), model_, SLOT(clearSuccessfulTasks()));
+
+    onModelReset();
+    connect(model_, SIGNAL(modelReset()), this, SLOT(onModelReset()));
+}
+
+void CloneTasksDialog::updateTasks()
+{
+    model_->updateTasks();
+}
+
+void CloneTasksDialog::onModelReset()
+{
+    if (model_->rowCount() == 0) {
+        stack_->setCurrentIndex(INDEX_EMPTY_VIEW);
+    } else {
+        stack_->setCurrentIndex(INDEX_TASKS_VIEW);
+        //table_->justifyColumnWidth();
+    }
+}
+
+
+void CloneTasksDialog::createEmptyView()
+{
+    empty_view_ = new QWidget(this);
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    empty_view_->setLayout(layout);
+
+    QLabel *label = new QLabel;
+    label->setText(tr("No download tasks right now."));
+    label->setAlignment(Qt::AlignCenter);
+
+    layout->addWidget(label);
+}
diff --git a/src/ui/clone-tasks-dialog.h b/src/ui/clone-tasks-dialog.h
new file mode 100644 (file)
index 0000000..13751cd
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SEAFILE_CLIENT_CLONE_TASKS_DIALOG_H
+#define SEAFILE_CLIENT_CLONE_TASKS_DIALOG_H
+
+#include <QDialog>
+#include "ui_clone-tasks-dialog.h"
+
+class QTimer;
+class QStackedWidget;
+
+class CloneTask;
+class CloneTasksTableView;
+class CloneTasksTableModel;
+
+class CloneTasksDialog : public QDialog,
+                         public Ui::CloneTasksDialog
+{
+    Q_OBJECT
+
+public:
+    CloneTasksDialog(QWidget *parent=0);
+    void updateTasks();
+
+private slots:
+    void onModelReset();
+
+private:
+    void createEmptyView();
+    void addTaskItem(const CloneTask& task);
+
+    QStackedWidget *stack_;
+    CloneTasksTableView *table_;
+    CloneTasksTableModel *model_;
+    QWidget *empty_view_;
+};
+
+
+#endif // SEAFILE_CLIENT_CLONE_TASKS_DIALOG_H
diff --git a/src/ui/clone-tasks-table-model.cpp b/src/ui/clone-tasks-table-model.cpp
new file mode 100644 (file)
index 0000000..b745764
--- /dev/null
@@ -0,0 +1,140 @@
+#include <QTimer>
+#include <QDir>
+
+#include "QtAwesome.h"
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "rpc/clone-task.h"
+#include "clone-tasks-table-model.h"
+
+namespace {
+
+const int kUpdateTasksInterval = 1000;
+
+enum {
+    COLUMN_NAME = 0,
+    COLUMN_WORK_TREE,
+    COLUMN_STATE,
+    MAX_COLUMN,
+};
+
+} // namespace
+
+CloneTasksTableModel::CloneTasksTableModel(QObject *parent)
+    : QAbstractTableModel(parent)
+{
+    update_timer_ = new QTimer(this);
+    connect(update_timer_, SIGNAL(timeout()), this, SLOT(updateTasks()));
+    update_timer_->start(kUpdateTasksInterval);
+
+    updateTasks();
+}
+
+void CloneTasksTableModel::updateTasks()
+{
+    std::vector<CloneTask> tasks;
+    int ret = seafApplet->rpcClient()->getCloneTasks(&tasks);
+    if (ret < 0) {
+        qDebug("failed to get clone tasks");
+        return;
+    }
+
+    beginResetModel();
+    if (tasks_.size() != tasks.size()) {
+        tasks_ = tasks;
+        endResetModel();
+        return;
+    }
+
+    for (int i = 0, n = tasks.size(); i < n; i++) {
+        if (tasks_[i] == tasks[i]) {
+            continue;
+        }
+
+        tasks_[i] = tasks[i];
+        QModelIndex start = QModelIndex().child(i, 0);
+        QModelIndex stop = QModelIndex().child(i, MAX_COLUMN - 1);
+        emit dataChanged(start, stop);
+    }
+    endResetModel();
+}
+
+int CloneTasksTableModel::rowCount(const QModelIndex& parent) const
+{
+    return tasks_.size();
+}
+
+int CloneTasksTableModel::columnCount(const QModelIndex& parent) const
+{
+    return MAX_COLUMN;
+}
+
+QVariant CloneTasksTableModel::data(const QModelIndex & index, int role) const
+{
+    if (!index.isValid()) {
+        return QVariant();
+    }
+
+    if (role != Qt::DisplayRole) {
+        return QVariant();
+    }
+
+    const CloneTask &task = tasks_[index.row()];
+
+    int column = index.column();
+
+    if (column == COLUMN_NAME) {
+        return task.repo_name;
+    } else if (column == COLUMN_WORK_TREE) {
+        return QDir::toNativeSeparators(task.worktree);
+    } else if (column == COLUMN_STATE) {
+        if (task.error_str.length() > 0) {
+            return task.error_str;
+        } else {
+            return task.state_str;
+        }
+    }
+
+    return QVariant();
+}
+
+QVariant CloneTasksTableModel::headerData(int section,
+                                          Qt::Orientation orientation,
+                                          int role) const
+{
+    if (orientation == Qt::Vertical) {
+        return QVariant();
+    }
+
+    if (section == COLUMN_NAME) {
+        if (role == Qt::DisplayRole) {
+            return tr("Library");
+        }
+        //else if (role == Qt::DecorationRole) {
+        //    return awesome->icon(icon_cloud);
+        //}
+    } else if (section == COLUMN_WORK_TREE) {
+        if (role == Qt::DisplayRole) {
+            return tr("Path");
+        }
+        //else if (role == Qt::DecorationRole) {
+        //   return awesome->icon(icon_folder_close_alt);
+        //}
+    }
+
+
+    return QVariant();
+}
+
+void CloneTasksTableModel::clearSuccessfulTasks()
+{
+    int n = tasks_.size();
+    for (int i = 0; i < n; i++) {
+        const CloneTask& task = tasks_[i];
+        if (task.isSuccessful()) {
+            QString error;
+            seafApplet->rpcClient()->removeCloneTask(task.repo_id, &error);
+        }
+    }
+}
diff --git a/src/ui/clone-tasks-table-model.h b/src/ui/clone-tasks-table-model.h
new file mode 100644 (file)
index 0000000..bf42efe
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef SEAFILE_CLIENT_CLONE_TASKS_TABLE_MODEL_H
+#define SEAFILE_CLIENT_CLONE_TASKS_TABLE_MODEL_H
+
+#include <QAbstractTableModel>
+#include <vector>
+
+#include "rpc/clone-task.h"
+
+class QTimer;
+
+class CloneTasksTableModel : public QAbstractTableModel
+{
+    Q_OBJECT
+
+public:
+    CloneTasksTableModel(QObject *parent=0);
+
+    int rowCount(const QModelIndex& parent=QModelIndex()) const;
+    int columnCount(const QModelIndex& parent=QModelIndex()) const;
+    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
+
+    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+    CloneTask taskAt(size_t i) const { return (i >= tasks_.size()) ? CloneTask() : tasks_[i]; }
+
+public slots:
+    void clearSuccessfulTasks();
+
+public slots:
+    void updateTasks();
+
+private:
+
+    std::vector<CloneTask> tasks_;
+    QTimer *update_timer_;
+};
+
+
+#endif // SEAFILE_CLIENT_CLONE_TASKS_TABLE_MODEL_H
diff --git a/src/ui/clone-tasks-table-view.cpp b/src/ui/clone-tasks-table-view.cpp
new file mode 100644 (file)
index 0000000..95c1526
--- /dev/null
@@ -0,0 +1,106 @@
+#include <QtGlobal>
+#include <QtWidgets>
+#include <QHeaderView>
+#include <QContextMenuEvent>
+
+#include "QtAwesome.h"
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "rpc/clone-task.h"
+#include "clone-tasks-table-model.h"
+#include "clone-tasks-table-view.h"
+
+
+CloneTasksTableHeader::CloneTasksTableHeader(QWidget *parent)
+    : QHeaderView(Qt::Horizontal, parent)
+{
+    sectionResizeMode(QHeaderView::Stretch);
+    setHighlightSections(false);
+}
+
+CloneTasksTableView::CloneTasksTableView(QWidget *parent)
+    : QTableView(parent)
+{
+    setHorizontalHeader(new CloneTasksTableHeader(this));
+    setSelectionBehavior(QAbstractItemView::SelectRows);
+    verticalHeader()->hide();
+
+    horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
+
+    createContextMenu();
+}
+
+void CloneTasksTableView::contextMenuEvent(QContextMenuEvent *event)
+{
+    QPoint pos = event->pos();
+    int row = rowAt(pos.y());
+    qDebug("row = %d\n", row);
+    if (row == -1) {
+        return;
+    }
+
+    CloneTasksTableModel *model = (CloneTasksTableModel *)this->model();
+
+    CloneTask task = model->taskAt(row);
+
+    prepareContextMenu(task);
+    pos = viewport()->mapToGlobal(pos);
+    context_menu_->exec(pos);
+}
+
+void CloneTasksTableView::prepareContextMenu(const CloneTask& task)
+{
+    if (task.isCancelable()) {
+        cancel_task_action_->setVisible(true);
+        cancel_task_action_->setData(task.repo_id);
+    } else {
+        cancel_task_action_->setVisible(false);
+    }
+
+    if (task.isRemovable()) {
+        remove_task_action_->setVisible(true);
+        remove_task_action_->setData(task.repo_id);
+    } else {
+        remove_task_action_->setVisible(false);
+    }
+}
+
+void CloneTasksTableView::createContextMenu()
+{
+    context_menu_ = new QMenu(this);
+
+    cancel_task_action_ = new QAction(tr("Cancel this task"), this);
+    cancel_task_action_->setIcon(awesome->icon(icon_remove));
+    cancel_task_action_->setStatusTip(tr("cancel this task"));
+    cancel_task_action_->setIconVisibleInMenu(true);
+    connect(cancel_task_action_, SIGNAL(triggered()), this, SLOT(cancelTask()));
+    context_menu_->addAction(cancel_task_action_);
+
+    remove_task_action_ = new QAction(tr("Remove this task"), this);
+    remove_task_action_->setIcon(awesome->icon(icon_remove));
+    remove_task_action_->setStatusTip(tr("Remove this task"));
+    remove_task_action_->setIconVisibleInMenu(true);
+    connect(remove_task_action_, SIGNAL(triggered()), this, SLOT(removeTask()));
+    context_menu_->addAction(remove_task_action_);
+}
+
+void CloneTasksTableView::cancelTask()
+{
+    QString repo_id = cancel_task_action_->data().toString();
+    QString error;
+    if (seafApplet->rpcClient()->cancelCloneTask(repo_id, &error) < 0) {
+        seafApplet->warningBox(
+            tr("Failed to cancel this task:\n\n %1").arg(error), this);
+    }
+}
+
+void CloneTasksTableView::removeTask()
+{
+    QString repo_id = remove_task_action_->data().toString();
+    QString error;
+    if (seafApplet->rpcClient()->removeCloneTask(repo_id, &error) < 0) {
+        seafApplet->warningBox(
+            tr("Failed to remove this task:\n\n %1").arg(error), this);
+    }
+}
diff --git a/src/ui/clone-tasks-table-view.h b/src/ui/clone-tasks-table-view.h
new file mode 100644 (file)
index 0000000..96a6ac1
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef SEAFILE_CLIENT_CLONE_TASKS_TABLE_VIEW_H
+#define SEAFILE_CLIENT_CLONE_TASKS_TABLE_VIEW_H
+
+#include <QTableView>
+#include <QHeaderView>
+
+class QAction;
+class QMenu;
+class QContextMenuEvent;
+
+class CloneTask;
+
+class CloneTasksTableView : public QTableView
+{
+    Q_OBJECT
+
+public:
+    CloneTasksTableView(QWidget *parent=0);
+
+    void contextMenuEvent(QContextMenuEvent *event);
+
+private slots:
+    void cancelTask();
+    void removeTask();
+
+private:
+    void createContextMenu();
+    void prepareContextMenu(const CloneTask& task);
+
+    QAction *cancel_task_action_;
+    QAction *remove_task_action_;
+    QMenu *context_menu_;
+};
+
+class CloneTasksTableHeader : public QHeaderView {
+    Q_OBJECT
+    
+public:
+    CloneTasksTableHeader(QWidget *parent=0);
+};
+
+#endif // SEAFILE_CLIENT_CLONE_TASKS_TABLE_VIEW_H
diff --git a/src/ui/cloud-view.cpp b/src/ui/cloud-view.cpp
new file mode 100644 (file)
index 0000000..3ed6dea
--- /dev/null
@@ -0,0 +1,650 @@
+#include <QtGlobal>
+#include <vector>
+
+#include <QtWidgets>
+#include <QImage>
+#include <QWidget>
+
+#include "QtAwesome.h"
+#include "account-mgr.h"
+#include "account-view.h"
+#include "activities-tab.h"
+#include "clone-tasks-dialog.h"
+#include "create-repo-dialog.h"
+#include "customization-service.h"
+#include "main-window.h"
+#include "repos-tab.h"
+#include "rpc/rpc-client.h"
+#include "seafile-applet.h"
+#include "seafile-tab-widget.h"
+#include "search-tab.h"
+#include "server-status-dialog.h"
+#include "server-status-service.h"
+#include "starred-files-tab.h"
+#include "utils/paint-utils.h"
+#include "utils/utils-mac.h"
+#include "utils/utils-win.h"
+#include "utils/utils.h"
+
+#include "cloud-view.h"
+
+namespace
+{
+const int kRefreshStatusInterval = 1000;
+
+const int kIndexOfAccountView = 1;
+// const int kIndexOfToolBar = 2;
+const int kIndexOfTabWidget = 2;
+const char* kQuotaColorCritical = "#FF2A2A";
+const char* kQuotaColorWarning = "#FF9A2A";
+const char* kQuotaColorGood = "#92C87A";
+const char* kDrapInnerBorderColor = "#E4E4E4";
+const char* kDrapEnterBorderColor = "#ED6C00";
+
+enum {
+    TAB_INDEX_REPOS = 0,
+    TAB_INDEX_STARRED_FILES,
+    TAB_INDEX_ACTIVITIES,
+    TAB_INDEX_SEARCH,
+};
+
+QString translateTransferRate(int rate)
+{
+    QString unit;
+    QString display_rate;
+    double kbps = ((double)rate) / 1024;
+    if (kbps >= 1024) {
+        unit = "MB/s";
+        double mbps = kbps / 1024;
+        if (mbps < 10) {
+            display_rate = QString::number(mbps, 'f', 1);
+        } else {
+            display_rate = QString::number(int(mbps));
+        }
+    }
+    else {
+        display_rate = kbps;
+        unit = "kB/s";
+        display_rate = QString::number(int(kbps));
+    }
+
+    return QString("%1 %2")
+        .arg(display_rate)
+        .arg(unit);
+}
+}
+
+CloudView::CloudView(QWidget* parent)
+    : QWidget(parent), clone_task_dialog_(NULL)
+
+{
+    setupUi(this);
+
+    int marginTop = 0;
+    if (shouldUseFramelessWindow()) {
+        marginTop = 0;
+    }
+#ifdef Q_OS_MAC
+    marginTop = 0;
+#endif
+
+    layout()->setContentsMargins(1, marginTop, 1, 0);
+
+    // Setup widgets from top down
+    setupHeader();
+
+    createAccountView();
+
+    createTabs();
+
+    // tool bar have to be created after tabs, since some of the toolbar
+    // actions are provided by the tabs
+    // createToolBar();
+
+    setupDropArea();
+
+    setupFooter();
+
+    QVBoxLayout* vlayout = (QVBoxLayout*)layout();
+    vlayout->insertWidget(kIndexOfAccountView, account_view_);
+    vlayout->insertWidget(kIndexOfTabWidget, tabs_);
+
+    if (shouldUseFramelessWindow()) {
+        resizer_ = new QSizeGrip(this);
+        resizer_->resize(resizer_->sizeHint());
+    }
+
+    refresh_status_bar_timer_ = new QTimer(this);
+    connect(refresh_status_bar_timer_, SIGNAL(timeout()), this,
+            SLOT(refreshStatusBar()));
+
+    AccountManager* account_mgr = seafApplet->accountManager();
+    connect(account_mgr, SIGNAL(accountsChanged()), this,
+            SLOT(onAccountChanged()));
+    connect(account_mgr, SIGNAL(accountInfoUpdated(const Account&)), this,
+            SLOT(onAccountInfoUpdated(const Account&)));
+
+    if (!shouldUseFramelessWindow()) {
+        mHeader->setVisible(false);
+    }
+
+    connect(ServerStatusService::instance(), SIGNAL(serverStatusChanged()),
+            this, SLOT(refreshServerStatus()));
+    connect(CustomizationService::instance(),
+            SIGNAL(serverLogoFetched(const QUrl&)), this,
+            SLOT(onServerLogoFetched(const QUrl&)));
+
+    QTimer::singleShot(0, this, SLOT(onAccountChanged()));
+}
+
+void CloudView::setupHeader()
+{
+    setupLogoAndBrand();
+
+    mMinimizeBtn->setText("");
+    mMinimizeBtn->setToolTip(tr("Minimize"));
+    mMinimizeBtn->setIcon(awesome->icon(icon_minus, QColor("#808081")));
+    connect(mMinimizeBtn, SIGNAL(clicked()), this,
+            SLOT(onMinimizeBtnClicked()));
+
+    mCloseBtn->setText("");
+    mCloseBtn->setToolTip(tr("Close"));
+    mCloseBtn->setIcon(awesome->icon(icon_remove, QColor("#808081")));
+    connect(mCloseBtn, SIGNAL(clicked()), this, SLOT(onCloseBtnClicked()));
+
+    // Handle mouse move event
+    mHeader->installEventFilter(this);
+}
+
+
+void CloudView::createAccountView()
+{
+    account_view_ = new AccountView;
+// #ifdef Q_OS_MAC
+//     account_view_->setContentsMargins(0, 0, 0, -8);
+// #else
+//     account_view_->setContentsMargins(0, -8, 0, -8);
+// #endif
+    connect(account_view_, SIGNAL(refresh()),
+            this, SLOT(onRefreshClicked()));
+}
+
+void CloudView::createTabs()
+{
+    tabs_ = new SeafileTabWidget;
+    // tabs_ = new QTabWidget;
+
+    repos_tab_ = new ReposTab;
+
+    QString base_icon_path = ":/images/tabs/";
+    QString highlighted_base_icon_path = ":/images/tabs/highlighted/";
+    tabs_->addTab(repos_tab_, tr("Libraries"),
+                  base_icon_path + "library-normal.png",
+                  highlighted_base_icon_path + "library-orange.png");
+
+    starred_files_tab_ = new StarredFilesTab;
+    tabs_->addTab(starred_files_tab_, tr("Starred"),
+                  base_icon_path + "star-normal.png",
+                  highlighted_base_icon_path + "star-orange.png");
+
+    activities_tab_ = new ActivitiesTab;
+
+    search_tab_ = new SearchTab;
+
+    connect(tabs_, SIGNAL(currentTabChanged(int)), this,
+            SLOT(onTabChanged(int)));
+
+    showProperTabs();
+    // bool has_pro_account = hasAccount() &&
+    // seafApplet->accountManager()->accounts().front().isPro();
+    // if (has_pro_account) {
+    //     addActivitiesTab();
+    // }
+}
+
+void CloudView::setupDropArea()
+{
+    mDropArea->setAcceptDrops(true);
+    mDropArea->installEventFilter(this);
+    connect(mSelectFolderBtn, SIGNAL(clicked()), this,
+            SLOT(chooseFolderToSync()));
+}
+
+void CloudView::setupFooter()
+{
+    // mDownloadTasksInfo->setText("0");
+    // mDownloadTasksBtn->setIcon(QIcon(":/images/toobar/download-gray.png"));
+    // mDownloadTasksBtn->setToolTip(tr("Show download tasks"));
+    // connect(mDownloadTasksBtn, SIGNAL(clicked()), this,
+    // SLOT(showCloneTasksDialog()));
+
+    mServerStatusBtn->setIconSize(QSize(10, 10));
+    connect(mServerStatusBtn, SIGNAL(clicked()), this,
+            SLOT(showServerStatusDialog()));
+
+    // mDownloadRateArrow->setText(QChar(icon_arrow_down));
+    // mDownloadRateArrow->setFont(awesome->font(16));
+    mDownloadRateArrow->setPixmap(QIcon(":/images/main-panel/download.png").pixmap(10));
+    mDownloadRateArrow->setAlignment(Qt::AlignVCenter);
+    mDownloadRate->setText("0 kB/s");
+    mDownloadRate->setToolTip(tr("current download rate"));
+    mDownloadRate->setAlignment(Qt::AlignVCenter | Qt::AlignRight);
+
+    // mUploadRateArrow->setText(QChar(icon_arrow_up));
+    // mUploadRateArrow->setFont(awesome->font(16));
+    mUploadRateArrow->setPixmap(QIcon(":/images/main-panel/upload.png").pixmap(10));
+    mUploadRateArrow->setAlignment(Qt::AlignVCenter);
+    mUploadRate->setText("0 kB/s");
+    mUploadRate->setToolTip(tr("current upload rate"));
+    mUploadRate->setAlignment(Qt::AlignVCenter | Qt::AlignRight);
+
+    mStorageUsage->reset();
+    mStorageUsage->setAlignment(Qt::AlignVCenter);
+}
+
+void CloudView::chooseFolderToSync()
+{
+    QString msg = tr("Please Choose a folder to sync");
+#if defined(Q_OS_WIN32)
+    QString parent_dir = "C:\\";
+#else
+    QString parent_dir = QDir::homePath();
+#endif
+    QString dir = QFileDialog::getExistingDirectory(
+        this, msg, parent_dir,
+        QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+    if (dir.isEmpty()) {
+        return;
+    }
+
+    showCreateRepoDialog(dir);
+}
+
+void CloudView::showCreateRepoDialog(const QString& path)
+{
+    const std::vector<Account>& accounts =
+        seafApplet->accountManager()->accounts();
+    if (accounts.empty()) {
+        return;
+    }
+
+    CreateRepoDialog* dialog =
+        new CreateRepoDialog(accounts[0], path, repos_tab_, this);
+
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->show();
+    dialog->raise();
+    dialog->activateWindow();
+}
+
+void CloudView::onMinimizeBtnClicked()
+{
+    seafApplet->mainWindow()->showMinimized();
+}
+
+void CloudView::onCloseBtnClicked()
+{
+    seafApplet->mainWindow()->hide();
+}
+
+bool CloudView::eventFilter(QObject* obj, QEvent* event)
+{
+    if (obj == mHeader) {
+        static QPoint oldPos;
+        if (event->type() == QEvent::MouseButtonPress) {
+            QMouseEvent* ev = (QMouseEvent*)event;
+            oldPos = ev->globalPos();
+
+            return true;
+        }
+        else if (event->type() == QEvent::MouseMove) {
+            QMouseEvent* ev = (QMouseEvent*)event;
+            const QPoint delta = ev->globalPos() - oldPos;
+
+            MainWindow* win = seafApplet->mainWindow();
+            win->move(win->x() + delta.x(), win->y() + delta.y());
+
+            oldPos = ev->globalPos();
+            return true;
+        }
+    }
+    else if (obj == mDropArea) {
+        if (event->type() == QEvent::DragEnter) {
+            QDragEnterEvent* ev = (QDragEnterEvent*)event;
+            if (ev->mimeData()->hasUrls() &&
+                ev->mimeData()->urls().size() == 1) {
+                const QUrl url = ev->mimeData()->urls().at(0);
+                if (url.scheme() == "file") {
+                    QString path = url.toLocalFile();
+#if defined(Q_OS_MAC) && (QT_VERSION <= QT_VERSION_CHECK(5, 4, 0))
+                    path = utils::mac::fix_file_id_url(path);
+#endif
+                    if (QFileInfo(path).isDir()) {
+                        QString style =
+                            QString("QFrame#mDropInner {border: 1.5px dashed %1;}")
+                                .arg(kDrapEnterBorderColor);
+                        mDropInner->setStyleSheet(style);
+                        ev->acceptProposedAction();
+                    }
+                }
+            }
+            return true;
+        }
+        else if (event->type() == QEvent::Drop) {
+            QDropEvent* ev = (QDropEvent*)event;
+            const QUrl url = ev->mimeData()->urls().at(0);
+            QString path = url.toLocalFile();
+#if defined(Q_OS_MAC) && (QT_VERSION <= QT_VERSION_CHECK(5, 4, 0))
+            path = utils::mac::fix_file_id_url(path);
+#endif
+            ev->setDropAction(Qt::CopyAction);
+            ev->accept();
+            QString style =
+                QString("QFrame#mDropInner {border: 1.5px dashed %1;}")
+                    .arg(kDrapInnerBorderColor);
+            mDropInner->setStyleSheet(style);
+            showCreateRepoDialog(path);
+            return true;
+        }
+        else if (event->type() == QEvent::DragLeave) {
+            QDragLeaveEvent* ev = static_cast<QDragLeaveEvent*>(event);
+            dragLeaveEvent(ev);
+            QString style =
+                QString("QFrame#mDropInner {border: 1.5px dashed %1;}")
+                    .arg(kDrapInnerBorderColor);
+            mDropInner->setStyleSheet(style);
+            return true;
+        }
+    }
+
+    return QWidget::eventFilter(obj, event);
+}
+
+CloneTasksDialog* CloudView::cloneTasksDialog()
+{
+    if (clone_task_dialog_ == NULL) {
+        clone_task_dialog_ = new CloneTasksDialog;
+    }
+
+    return clone_task_dialog_;
+}
+
+bool CloudView::hasAccount()
+{
+    return seafApplet->accountManager()->hasAccount();
+}
+
+void CloudView::showEvent(QShowEvent* event)
+{
+    QWidget::showEvent(event);
+
+    refresh_status_bar_timer_->start(kRefreshStatusInterval);
+}
+
+void CloudView::hideEvent(QHideEvent* event)
+{
+    QWidget::hideEvent(event);
+    refresh_status_bar_timer_->stop();
+}
+
+
+void CloudView::refreshTasksInfo()
+{
+    int count = 0;
+    if (seafApplet->rpcClient()->getCloneTasksCount(&count) < 0) {
+        return;
+    }
+
+    // mDownloadTasksInfo->setText(QString::number(count));
+}
+
+void CloudView::refreshServerStatus()
+{
+    ServerStatusService* service = ServerStatusService::instance();
+    QString tool_tip;
+    if (service->allServersConnected()) {
+        tool_tip = tr("all servers connected");
+    }
+    else if (service->allServersDisconnected()) {
+        tool_tip = tr("no server connected");
+    }
+    else {
+        tool_tip = tr("some servers not connected");
+    }
+
+    if (!service->allServersConnected()) {
+        mServerStatusBtn->setIcon(
+            QIcon(":/images/main-panel/network-error.png"));
+        mServerStatusBtn->show();
+    } else {
+        mServerStatusBtn->hide();
+    }
+
+    mServerStatusBtn->setToolTip(tool_tip);
+}
+
+void CloudView::refreshTransferRate()
+{
+    int up_rate, down_rate;
+    if (seafApplet->rpcClient()->getUploadRate(&up_rate) < 0) {
+        return;
+    }
+
+    if (seafApplet->rpcClient()->getDownloadRate(&down_rate) < 0) {
+        return;
+    }
+
+    mUploadRate->setText(translateTransferRate(up_rate));
+    mDownloadRate->setText(translateTransferRate(down_rate));
+}
+
+void CloudView::refreshStatusBar()
+{
+    if (!seafApplet->mainWindow()->isVisible()) {
+        return;
+    }
+    refreshTasksInfo();
+    refreshTransferRate();
+}
+
+void CloudView::showCloneTasksDialog()
+{
+    // CloneTasksDialog dialog(this);
+    if (clone_task_dialog_ == NULL) {
+        clone_task_dialog_ = new CloneTasksDialog;
+    }
+
+    clone_task_dialog_->updateTasks();
+    clone_task_dialog_->show();
+    clone_task_dialog_->raise();
+    clone_task_dialog_->activateWindow();
+}
+
+void CloudView::showServerStatusDialog()
+{
+    ServerStatusDialog dialog(this);
+    dialog.exec();
+}
+
+void CloudView::onRefreshClicked()
+{
+    if (tabs_->currentIndex() == TAB_INDEX_REPOS) {
+        repos_tab_->refresh();
+    }
+    else if (tabs_->currentIndex() == TAB_INDEX_STARRED_FILES) {
+        starred_files_tab_->refresh();
+    }
+    else if (tabs_->currentIndex() == TAB_INDEX_ACTIVITIES) {
+        activities_tab_->refresh();
+    }
+    else if (tabs_->currentIndex() == TAB_INDEX_SEARCH) {
+        search_tab_->refresh();
+    }
+}
+
+void CloudView::resizeEvent(QResizeEvent* event)
+{
+    if (shouldUseFramelessWindow()) {
+        resizer_->move(rect().bottomRight() - resizer_->rect().bottomRight());
+        resizer_->raise();
+    }
+
+    tabs_->adjustTabsWidth(rect().width());
+}
+
+void CloudView::onServerLogoFetched(const QUrl& url)
+{
+    const Account& account = seafApplet->accountManager()->currentAccount();
+    if (account.isValid() && url.host() == account.serverUrl.host()) {
+        mLogo->setPixmap(
+            CustomizationService::instance()->getServerLogo(account));
+    }
+}
+
+void CloudView::setupLogoAndBrand()
+{
+    mLogo->setText("");
+    mLogo->setToolTip(getBrand());
+    QPixmap logo;
+    // We must get the pixmap from a QImage, otherwise the logo won't be
+    // updated when we switch between two accounts, one of which has custom
+    // logo and the other doesn't.
+    logo.convertFromImage(QImage(":/images/seafile-24.png"));
+    mLogo->setPixmap(logo);
+
+    mBrand->setText(getBrand());
+    mBrand->setToolTip(getBrand());
+}
+
+void CloudView::onAccountChanged()
+{
+    setupLogoAndBrand();
+    const Account& account = seafApplet->accountManager()->currentAccount();
+    if (account.isValid() && account.isPro()) {
+        if (!account.serverInfo.customBrand.isEmpty()) {
+            QString title = account.serverInfo.customBrand;
+            mBrand->setText(title);
+            mBrand->setToolTip(title);
+            mLogo->setToolTip(title);
+            if (seafApplet->mainWindow()) {
+                seafApplet->mainWindow()->setWindowTitle(title);
+            }
+        }
+
+        if (!account.serverInfo.customLogo.isEmpty()) {
+            mLogo->setPixmap(
+                CustomizationService::instance()->getServerLogo(account));
+        }
+    }
+
+    // refresh_action_->setEnabled(account.isValid());
+
+    showProperTabs();
+
+    repos_tab_->refresh();
+    starred_files_tab_->refresh();
+    if (seafApplet->accountManager()->currentAccount().isPro()) {
+        activities_tab_->refresh();
+    }
+    search_tab_->reset();
+
+    account_view_->onAccountChanged();
+    // we need update tab manually
+    onTabChanged(tabs_->currentIndex());
+
+    updateStorageUsage(account);
+}
+
+void CloudView::updateStorageUsage(const Account& account)
+{
+    if (!account.isValid()) {
+        mStorageUsage->hide();
+        return;
+    }
+    mStorageUsage->show();
+    const AccountInfo& info = account.accountInfo;
+    if (info.totalStorage > 0) {
+        mStorageUsage->setMaximum(info.totalStorage / 1000);
+        mStorageUsage->setValue(qMax(info.usedStorage / 1000, 3 * info.totalStorage / (100 * 1000)));
+        mStorageUsage->setVisible(true);
+        QString msg = ::readableFileSize(info.usedStorage) + "/" +
+                      ::readableFileSize(info.totalStorage);
+        mStorageUsage->setFormat(msg);
+        mStorageUsage->setToolTip(msg);
+        int percent = info.usedStorage * 100.0 / info.totalStorage;
+        QString color;
+        if (percent >= 80) {
+            color = kQuotaColorCritical;
+        }
+        else if (percent >= 50) {
+            color = kQuotaColorWarning;
+        }
+        else {
+            color = kQuotaColorGood;
+        }
+        QString style =
+            QString("QProgressBar::chunk {background-color: %1; width: 3px;}")
+                .arg(color);
+        mStorageUsage->setStyleSheet(style);
+    }
+    else {
+        mStorageUsage->setVisible(false);
+        mStorageUsage->setToolTip("");
+    }
+    mStorageUsage->setTextVisible(false);
+}
+
+void CloudView::showProperTabs()
+{
+    const Account& account = seafApplet->accountManager()->currentAccount();
+    bool show_activities_tab = false;
+    bool show_search_tab = false;
+    if (tabs_->count() > 2) {
+        tabs_->removeTab(TAB_INDEX_SEARCH, search_tab_);
+        tabs_->removeTab(TAB_INDEX_ACTIVITIES, activities_tab_);
+    }
+    if (account.isPro()) {
+        show_activities_tab = true;
+        if (account.hasFileSearch()) {
+            show_search_tab = true;
+        }
+        if (show_activities_tab) {
+            tabs_->addTab(activities_tab_, tr("Activities"),
+                          ":/images/tabs/history-normal.png",
+                          ":/images/tabs/highlighted/history-orange.png");
+        }
+        if (show_search_tab) {
+            tabs_->addTab(search_tab_, tr("Search"),
+                          ":/images/tabs/search-normal.png",
+                          ":/images/tabs/highlighted/search-orange.png");
+        }
+    }
+    tabs_->adjustTabsWidth(rect().width());
+}
+
+void CloudView::onTabChanged(int index)
+{
+    bool enable_sync_with_any_folder = hasAccount() &&
+                                       !seafApplet->accountManager()
+                                            ->accounts()
+                                            .front()
+                                            .hasDisableSyncWithAnyFolder();
+    bool drop_area_visible = index == 0;
+    if (enable_sync_with_any_folder && drop_area_visible) {
+        mDropArea->setVisible(true);
+        mFooter->setStyleSheet("");
+    }
+    else {
+        mDropArea->setVisible(false);
+        mFooter->setStyleSheet(
+            "QFrame#mFooter { border-top: 1px solid #DCDCDE; }");
+    }
+}
+
+void CloudView::onAccountInfoUpdated(const Account& account)
+{
+    if (account == seafApplet->accountManager()->currentAccount()) {
+        updateStorageUsage(account);
+        account_view_->onAccountChanged();
+    }
+}
diff --git a/src/ui/cloud-view.h b/src/ui/cloud-view.h
new file mode 100644 (file)
index 0000000..34d27f6
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef SEAFILE_CLIENT_CLOUD_VIEW_H
+#define SEAFILE_CLIENT_CLOUD_VIEW_H
+
+#include <QWidget>
+#include "ui_cloud-view.h"
+
+class QTimer;
+class QShowEvent;
+class QHideEvent;
+class QToolButton;
+class QToolBar;
+class QSizeGrip;
+class QTabWidget;
+class QUrl;
+
+class SeafileTabWidget;
+class ReposTab;
+class StarredFilesTab;
+class ActivitiesTab;
+class SearchTab;
+class CloneTasksDialog;
+class AccountView;
+class Account;
+
+class CloudView : public QWidget,
+                  public Ui::CloudView
+{
+    Q_OBJECT
+public:
+    CloudView(QWidget *parent=0);
+
+    CloneTasksDialog* cloneTasksDialog();
+
+protected:
+    void showEvent(QShowEvent *event);
+    void hideEvent(QHideEvent *event);
+    void resizeEvent(QResizeEvent *event);
+    bool eventFilter(QObject *obj, QEvent *ev);
+
+public slots:
+    void showCloneTasksDialog();
+
+private slots:
+    void refreshStatusBar();
+    void showServerStatusDialog();
+    void onRefreshClicked();
+    void onMinimizeBtnClicked();
+    void onCloseBtnClicked();
+    void chooseFolderToSync();
+    void onAccountChanged();
+    void onTabChanged(int index);
+    void refreshServerStatus();
+    void onServerLogoFetched(const QUrl& url);
+    void onAccountInfoUpdated(const Account& account);
+
+private:
+    Q_DISABLE_COPY(CloudView)
+
+    bool hasAccount();
+
+    void setupHeader();
+    void setupLogoAndBrand();
+    void createAccountView();
+    void createTabs();
+    void setupDropArea();
+    void setupFooter();
+    void showProperTabs();
+
+    void refreshTasksInfo();
+    void refreshTransferRate();
+    void showCreateRepoDialog(const QString& path);
+    void updateStorageUsage(const Account& account);
+
+    QTimer *refresh_status_bar_timer_;
+
+    AccountView *account_view_;
+
+    SeafileTabWidget *tabs_;
+    ReposTab *repos_tab_;
+    StarredFilesTab *starred_files_tab_;
+    ActivitiesTab *activities_tab_;
+    SearchTab *search_tab_;
+
+    QSizeGrip *resizer_;
+
+    CloneTasksDialog* clone_task_dialog_;
+};
+
+
+#endif  // SEAFILE_CLIENT_CLOUD_VIEW_H
diff --git a/src/ui/create-repo-dialog.cpp b/src/ui/create-repo-dialog.cpp
new file mode 100644 (file)
index 0000000..a662d87
--- /dev/null
@@ -0,0 +1,241 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include <QUuid>
+
+#include "utils/utils.h"
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "repo-service.h"
+#include "api/requests.h"
+#include "api/api-error.h"
+#include "rpc/rpc-client.h"
+#include "ui/create-repo-dialog.h"
+#include "ui/repos-tab.h"
+
+CreateRepoDialog::CreateRepoDialog(const Account& account,
+                                   const QString& worktree,
+                                   ReposTab *repos_tab,
+                                   QWidget *parent)
+    : QDialog(parent),
+      path_(worktree),
+      request_(NULL),
+      account_(account),
+      repos_tab_(repos_tab)
+{
+    setupUi(this);
+    setWindowTitle(tr("Create a library"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+    setWindowIcon(QIcon(":/images/seafile.png"));
+
+#if defined(Q_OS_MAC)
+    layout()->setContentsMargins(6, 6, 6, 6);
+    layout()->setSpacing(5);
+#endif
+
+    mStatusText->setText("");
+
+    mDirectory->setText(worktree);
+    mName->setText(QDir(worktree).dirName());
+
+    connect(mChooseDirBtn, SIGNAL(clicked()), this, SLOT(chooseDirAction()));
+    connect(mOkBtn, SIGNAL(clicked()), this, SLOT(createAction()));
+
+    const QRect screen = QApplication::desktop()->screenGeometry();
+    move(screen.center() - this->rect().center());
+}
+
+CreateRepoDialog::~CreateRepoDialog()
+{
+    if (request_) {
+        request_->deleteLater();
+        request_ = nullptr;
+    }
+}
+
+void CreateRepoDialog::chooseDirAction()
+{
+    QString dir = QFileDialog::getExistingDirectory(this, tr("Please choose a directory"),
+                                                    mDirectory->text(),
+                                                    QFileDialog::ShowDirsOnly
+                                                    | QFileDialog::DontResolveSymlinks);
+    if (dir.isEmpty())
+        return;
+    mDirectory->setText(dir);
+    QDir d(dir);
+    mName->setText(d.dirName());
+}
+
+void CreateRepoDialog::setAllInputsEnabled(bool enabled)
+{
+    mOkBtn->setEnabled(enabled);
+    mChooseDirBtn->setEnabled(enabled);
+    mDirectory->setEnabled(enabled);
+    mName->setEnabled(enabled);
+    mEncrypteCheckBox->setEnabled(enabled);
+
+    bool password_enabled = (mEncrypteCheckBox->checkState() == Qt::Checked) && enabled;
+    mPassword->setEnabled(password_enabled);
+    mPasswordAgain->setEnabled(password_enabled);
+}
+
+void CreateRepoDialog::createAction()
+{
+    if (!validateInputs()) {
+        return;
+    }
+    mStatusText->setText(tr("Creating..."));
+
+    setAllInputsEnabled(false);
+
+    if (request_) {
+        request_->deleteLater();
+        request_ = nullptr;
+    }
+
+    if (!passwd_.isEmpty() && account_.isAtLeastVersion(4, 4, 0)) {
+        // TODO: check server version is at least 4.3.x ?
+        QString repo_id = QUuid::createUuid().toString().mid(1, 36);
+        QString magic, random_key, salt;
+
+        int enc_version = seafApplet->accountManager()->currentAccount().getEncryptedLibraryVersion();
+
+        if (seafApplet->rpcClient()->generateMagicAndRandomKey(
+                enc_version, repo_id, passwd_, &magic, &random_key, &salt) < 0) {
+            seafApplet->warningBox(tr("Failed to generate encryption key for this library"), this);
+            return;
+        }
+        // printf ("magic is %s, random_key is %s salt is %s\n", toCStr(magic), toCStr(random_key), toCStr(salt));
+
+        if (enc_version == 3) {
+            request_ = new CreateRepoRequest(
+                account_, name_, name_, enc_version, repo_id, magic, random_key, salt);
+        } else {
+            request_ = new CreateRepoRequest(
+                account_, name_, name_, enc_version, repo_id, magic, random_key);
+        }
+    } else {
+        request_ = new CreateRepoRequest(account_, name_, name_, passwd_);
+    }
+
+    connect(request_, SIGNAL(success(const RepoDownloadInfo&)),
+            this, SLOT(createSuccess(const RepoDownloadInfo&)));
+
+    connect(request_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(createFailed(const ApiError&)));
+
+    request_->send();
+}
+
+bool CreateRepoDialog::validateInputs()
+{
+    QString path;
+    QString passwd;
+    QString passwdAgain;
+    bool encrypted;
+
+    path = mDirectory->text();
+    if (path.isEmpty()) {
+        seafApplet->warningBox(tr("Please choose the directory to sync"), this);
+        return false;
+    }
+    if (!QDir(path).exists()) {
+        seafApplet->warningBox(tr("The folder %1 does not exist").arg(path), this);
+        return false;
+    }
+
+    if (mName->text().trimmed().isEmpty()) {
+        seafApplet->warningBox(tr("Please enter the name"), this);
+        return false;
+    }
+
+    encrypted = mEncrypteCheckBox->checkState() == Qt::Checked;
+    if (encrypted) {
+        if (mPassword->text().trimmed().isEmpty() ||
+            mPasswordAgain->text().trimmed().isEmpty()) {
+            seafApplet->warningBox(tr("Please enter the password"), this);
+            return false;
+        }
+
+        passwd = mPassword->text().trimmed();
+        passwdAgain = mPasswordAgain->text().trimmed();
+        if (passwd != passwdAgain) {
+            seafApplet->warningBox(tr("Passwords don't match"), this);
+            return false;
+        }
+        passwd_ = passwd;
+    } else {
+        passwd_ = QString::null;
+    }
+
+    QString error;
+    if (seafApplet->rpcClient()->checkPathForClone(path, &error) < 0) {
+        if (error.isEmpty()) {
+            error = tr("Unknown error");
+        }
+        seafApplet->warningBox(translateErrorMsg(error), this);
+        return false;
+    }
+
+    name_ = mName->text().trimmed();
+    path_ = mDirectory->text();
+    return true;
+}
+
+void CreateRepoDialog::createSuccess(const RepoDownloadInfo& info)
+{
+    QString error;
+
+    int ret = seafApplet->rpcClient()->cloneRepo(
+        info.repo_id,
+        info.repo_version,
+        info.relay_id,
+        info.repo_name,
+        path_,
+        info.token,
+        passwd_,
+        info.magic,
+        info.relay_addr,
+        info.relay_port,
+        info.email,
+        info.random_key,
+        info.enc_version,
+        info.more_info,
+        &error);
+
+    if (ret < 0) {
+        error = translateErrorMsg(error);
+        seafApplet->warningBox(tr("Failed to add download task:\n %1").arg(error), this);
+        setAllInputsEnabled(true);
+    } else {
+        repos_tab_->refresh();
+        done(QDialog::Accepted);
+    }
+}
+
+void CreateRepoDialog::createFailed(const ApiError& error)
+{
+    mStatusText->setText("");
+
+    QString msg = tr("Failed to create library on the server:\n%1").arg(error.toString());
+
+    seafApplet->warningBox(msg, this);
+
+    setAllInputsEnabled(true);
+}
+
+QString CreateRepoDialog::translateErrorMsg(const QString& error)
+{
+    if (error == "Worktree conflicts system path") {
+        return QObject::tr("The path \"%1\" conflicts with system path").arg(path_);
+    } else if (error == "Worktree conflicts existing repo") {
+        return QObject::tr("The path \"%1\" conflicts with an existing library").arg(path_);
+    }
+    return error;
+}
diff --git a/src/ui/create-repo-dialog.h b/src/ui/create-repo-dialog.h
new file mode 100644 (file)
index 0000000..18de0b2
--- /dev/null
@@ -0,0 +1,43 @@
+#include <QDialog>
+#include <QUrl>
+#include <QString>
+
+#include "ui_create-repo-dialog.h"
+#include "account.h"
+
+class CreateRepoRequest;
+class RepoDownloadInfo;
+class ApiError;
+class ReposTab;
+
+class CreateRepoDialog : public QDialog,
+                         public Ui::CreateRepoDialog
+{
+    Q_OBJECT
+public:
+    CreateRepoDialog(const Account& account,
+                     const QString& worktree,
+                     ReposTab *repos_tab,
+                     QWidget *parent=0);
+
+    ~CreateRepoDialog();
+
+private slots:
+    void createAction();
+    void chooseDirAction();
+    void createSuccess(const RepoDownloadInfo& info);
+    void createFailed(const ApiError& error);
+
+private:
+    Q_DISABLE_COPY(CreateRepoDialog);
+    bool validateInputs();
+    void setAllInputsEnabled(bool enabled);
+    QString translateErrorMsg(const QString& error);
+
+    QString path_;
+    QString name_;
+    QString passwd_;
+    CreateRepoRequest *request_;
+    Account account_;
+    ReposTab *repos_tab_;
+};
diff --git a/src/ui/download-repo-dialog.cpp b/src/ui/download-repo-dialog.cpp
new file mode 100644 (file)
index 0000000..8674450
--- /dev/null
@@ -0,0 +1,402 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QDirIterator>
+#include <QTimer>
+
+#include <jansson.h>
+
+#include "account-mgr.h"
+#include "settings-mgr.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "configurator.h"
+#include "api/requests.h"
+#include "api/api-error.h"
+#include "api/server-repo.h"
+#include "repo-service.h"
+#include "download-repo-dialog.h"
+
+namespace {
+const int kAlternativeTryTimes = 20;
+bool inline isPathInWorktree(const QString& worktree, const QString &path)
+{
+    if (path == worktree) {
+        return true;
+    }
+    QDir dir(worktree);
+    if (dir.relativeFilePath(QFileInfo(path).absoluteFilePath()).startsWith("."))
+        return false;
+    return true;
+}
+
+bool isPathConflictWithExistingRepo(const QString &path, QString *repo_name) {
+    RepoService::instance()->refreshLocalRepoList();
+    const std::vector<LocalRepo> & repos = RepoService::instance()->localRepos();
+    for (unsigned i = 0; i < repos.size(); ++i) {
+        // compare case insensitive file names as well
+        if (QFileInfo(repos[i].worktree) == QFileInfo(path)) {
+            *repo_name = repos[i].name;
+            return true;
+        }
+    }
+    return false;
+}
+
+QString getAlternativePath(const QString &dir_path, const QString &name) {
+    QDir dir = QDir(dir_path);
+    QFileInfo file;
+    file = QFileInfo(dir.filePath(name));
+    int i;
+    for (i = 1; i < kAlternativeTryTimes; ++i) {
+        if (!file.exists() && dir.mkdir(file.fileName()))
+            return file.absoluteFilePath();
+        file = QFileInfo(dir.filePath(name + "-" + QString::number(i)));
+    }
+
+    return QString();
+}
+
+inline QString getOperatingText(const ServerRepo &repo) {
+    if (!repo.isSubfolder()) {
+        return QObject::tr("Sync this library to:");
+    } else {
+        return QObject::tr("Sync this folder to:");
+    }
+}
+} // anonymous namespace
+
+DownloadRepoDialog::DownloadRepoDialog(const Account& account,
+                                       const ServerRepo& repo,
+                                       const QString& password,
+                                       QWidget *parent)
+    : QDialog(parent),
+      repo_(repo),
+      account_(account),
+      merge_without_question_(false),
+      resync_mode_(false)
+{
+    manual_merge_mode_ = false;
+    setupUi(this);
+    if (!repo.isSubfolder()) {
+        setWindowTitle(tr("Sync library \"%1\"").arg(repo_.name));
+    }
+    else {
+        setWindowTitle(tr("Sync folder \"%1\"").arg(repo.parent_path));
+    }
+    mDirectory->setPlaceholderText(getOperatingText(repo_));
+    mDirectory->setReadOnly(true);
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+    setWindowIcon(QIcon(":/images/seafile.png"));
+
+    mRepoIcon->setPixmap(repo.getPixmap());
+    mRepoName->setText(repo_.name);
+    mOperationText->setText(tr("Sync to folder:"));
+
+    if (repo_.encrypted) {
+        if (!password.isEmpty()) {
+            mPassword->setText(password);
+            mPassword->setReadOnly(true);
+        }
+        mPassword->setVisible(true);
+        mPasswordLabel->setVisible(true);
+    } else {
+        mPassword->setVisible(false);
+        mPasswordLabel->setVisible(false);
+    }
+
+    int height = 250;
+#if defined(Q_OS_MAC)
+    layout()->setContentsMargins(8, 9, 9, 5);
+    layout()->setSpacing(6);
+    verticalLayout_3->setSpacing(6);
+#endif
+    if (repo.encrypted) {
+        height += 50;
+    }
+    setMinimumHeight(height);
+    setMaximumHeight(height);
+
+    setDirectoryText(seafApplet->configurator()->worktreeDir());
+
+    connect(mSwitchModeHint, SIGNAL(linkActivated(const QString &)),
+            this, SLOT(switchMode()));
+
+    updateSyncMode();
+
+    mMergeHint->hide();
+
+    connect(mChooseDirBtn, SIGNAL(clicked()), this, SLOT(chooseDirAction()));
+    connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkBtnClicked()));
+
+    QTimer::singleShot(1000, this, SLOT(startResync()));
+}
+
+void DownloadRepoDialog::startResync()
+{
+    if (!resync_mode_) {
+        return;
+    }
+    onOkBtnClicked();
+}
+
+void DownloadRepoDialog::switchMode()
+{
+    manual_merge_mode_ = !manual_merge_mode_;
+
+    QString path = mDirectory->text().trimmed();
+    if (!path.isEmpty()) {
+        // from download new to merge existing
+        if (manual_merge_mode_) {
+            setDirectoryText(::pathJoin(path, repo_.name));
+        } else {
+            // from merge existing to download new
+            if (::getBaseName(path) == repo_.name) {
+                setDirectoryText(::getParentPath(path));
+            }
+        }
+    }
+
+    updateSyncMode();
+}
+
+void DownloadRepoDialog::updateSyncMode()
+{
+    if (account_.hasDisableSyncWithAnyFolder()) {
+        sync_with_existing_ = false;
+        manual_merge_mode_ = false;
+        mOperationText->setVisible(false);
+        mSwitchModeHint->setVisible(false);
+        return;
+    }
+    QString switch_hint_text;
+    QString op_text;
+    const QString link_template = "<a style=\"color:#FF9A2A\" href=\"#\">%1</a>";
+
+    QString OR = tr("or");
+    if (!manual_merge_mode_) {
+        op_text = getOperatingText(repo_);
+        sync_with_existing_ = false;
+
+        QString link = link_template.arg(tr("sync with an existing folder"));
+        switch_hint_text = QString("%1 %2").arg(OR).arg(link);
+
+    } else {
+        QString link = link_template.arg(tr("create a new sync folder"));
+        switch_hint_text = QString("%1 %2").arg(OR).arg(link);
+        sync_with_existing_ = true;
+
+        op_text = tr("Sync with this existing folder:");
+
+        if (!alternative_path_.isNull()) {
+            setDirectoryText(alternative_path_);
+        }
+    }
+
+    mOperationText->setText(op_text);
+    mSwitchModeHint->setText(switch_hint_text);
+}
+
+void DownloadRepoDialog::setDirectoryText(const QString& path)
+{
+    QString text = path;
+    if (text.endsWith("/")) {
+        text.resize(text.size() - 1);
+    }
+
+    mDirectory->setText(text);
+
+    if (manual_merge_mode_) {
+        alternative_path_ = text;
+    }
+}
+
+void DownloadRepoDialog::chooseDirAction()
+{
+    const QString &wt = seafApplet->configurator()->worktreeDir();
+    QString dir = QFileDialog::getExistingDirectory(this, tr("Please choose a folder"),
+                                                    wt.toUtf8().data(),
+                                                    QFileDialog::ShowDirsOnly
+                                                    | QFileDialog::DontResolveSymlinks);
+    if (dir.isEmpty())
+        return;
+    setDirectoryText(dir);
+}
+
+void DownloadRepoDialog::onOkBtnClicked()
+{
+    if (!validateInputs()) {
+        return;
+    }
+
+    setAllInputsEnabled(false);
+
+    DownloadRepoRequest *req = new DownloadRepoRequest(account_, repo_.id, repo_.readonly);
+    connect(req, SIGNAL(success(const RepoDownloadInfo&)),
+            this, SLOT(onDownloadRepoRequestSuccess(const RepoDownloadInfo&)));
+    connect(req, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onDownloadRepoRequestFailed(const ApiError&)));
+    req->send();
+}
+
+bool DownloadRepoDialog::validateInputDirectory()
+{
+    QDir dir(mDirectory->text());
+    if (!dir.exists()) {
+        seafApplet->warningBox(tr("The folder does not exist"));
+        return false;
+    }
+    return true;
+}
+
+bool DownloadRepoDialog::validateInputs()
+{
+    setDirectoryText(mDirectory->text().trimmed());
+    if (mDirectory->text().isEmpty()) {
+        seafApplet->warningBox(tr("Please choose the folder to sync."));
+        return false;
+    }
+    if (account_.hasDisableSyncWithAnyFolder() &&
+        !isPathInWorktree(seafApplet->configurator()->worktreeDir(), mDirectory->text())) {
+        seafApplet->warningBox(
+            tr("Your organization disables putting a library outside %1 folder.").arg(getBrand()));
+        return false;
+    }
+    if (repo_.encrypted) {
+        mPassword->setText(mPassword->text().trimmed());
+        if (mPassword->text().isEmpty()) {
+            seafApplet->warningBox(tr("Please enter the password"));
+            return false;
+        }
+    }
+
+    if (!validateInputDirectory()) {
+        return false;
+    }
+
+    if (manual_merge_mode_) {
+        return true;
+    }
+
+    sync_with_existing_ = false;
+    alternative_path_ = "";
+
+    QString path = QDir(mDirectory->text()).absoluteFilePath(repo_.name);
+    QFileInfo fileinfo = QFileInfo(path);
+    if (fileinfo.exists()) {
+        sync_with_existing_ = true;
+        // exist and but not a directory ?
+        if (!fileinfo.isDir()) {
+            seafApplet->warningBox(
+                tr("Conflicting with existing file \"%1\", please choose a different folder.").arg(path));
+            return false;
+        }
+        // exist and but conflicting?
+        QString repo_name;
+        if (isPathConflictWithExistingRepo(path, &repo_name)) {
+            seafApplet->warningBox(
+                tr("Conflicting with existing library \"%1\", please choose a different folder.").arg(repo_name));
+            return false;
+        }
+        QMessageBox::StandardButton ret = merge_without_question_
+            ? QMessageBox::Yes
+            : seafApplet->yesNoCancelBox(
+                tr("The folder \"%1\" already exists. Are you sure to sync with it (contents will be merged)?")
+                .arg(path) + QString("<br/><br/><small>%1</small>").arg(tr("Click No to sync with a new folder instead")),
+                this, QMessageBox::Yes);
+        if (ret == QMessageBox::Cancel)
+            return false;
+        if (ret == QMessageBox::No) {
+            QString new_path = getAlternativePath(mDirectory->text(), repo_.name);
+            if (new_path.isEmpty()) {
+                seafApplet->warningBox(tr("Unable to find an alternative folder name").arg(path));
+                return false;
+            }
+            alternative_path_ = new_path;
+        }
+    }
+
+    return true;
+}
+
+void DownloadRepoDialog::setAllInputsEnabled(bool enabled)
+{
+    mDirectory->setEnabled(enabled);
+    mChooseDirBtn->setEnabled(enabled);
+    mPassword->setEnabled(enabled);
+    mOkBtn->setEnabled(enabled);
+}
+
+void DownloadRepoDialog::onDownloadRepoRequestSuccess(const RepoDownloadInfo& info)
+{
+    QString worktree = mDirectory->text();
+    QString password = repo_.encrypted ? mPassword->text() : QString();
+    int ret = 0;
+    QString error;
+
+    if (sync_with_existing_) {
+        if (alternative_path_.isEmpty())
+            worktree = QDir(worktree).absoluteFilePath(repo_.name);
+        else
+            worktree = alternative_path_;
+        ret = seafApplet->rpcClient()->cloneRepo(info.repo_id, info.repo_version,
+                                                 info.relay_id,
+                                                 repo_.name, worktree,
+                                                 info.token, password,
+                                                 info.magic, info.relay_addr,
+                                                 info.relay_port, info.email,
+                                                 info.random_key, info.enc_version,
+                                                 info.more_info,
+                                                 &error);
+    } else {
+        ret = seafApplet->rpcClient()->downloadRepo(info.repo_id, info.repo_version,
+                                                    info.relay_id,
+                                                    repo_.name, worktree,
+                                                    info.token, password,
+                                                    info.magic, info.relay_addr,
+                                                    info.relay_port, info.email,
+                                                    info.random_key, info.enc_version,
+                                                    info.more_info,
+                                                    &error);
+    }
+
+    if (ret < 0) {
+        if (error == "Worktree conflicts system path") {
+            error = QObject::tr("The path \"%1\" conflicts with system path").arg(worktree);
+        } else if (error == "Worktree conflicts existing repo") {
+            error = QObject::tr("The path \"%1\" conflicts with an existing library").arg(worktree);
+        } else if (error == "Library name contains invalid characters such as ':', '*', '|', '?'") {
+            error = QObject::tr("Library name contains invalid characters such as ':', '*', '|', '?'");
+        }
+        seafApplet->warningBox(tr("Failed to add download task:\n %1").arg(error), this);
+        setAllInputsEnabled(true);
+    } else {
+        done(QDialog::Accepted);
+    }
+}
+
+
+void DownloadRepoDialog::onDownloadRepoRequestFailed(const ApiError& error)
+{
+    QString msg = tr("Failed to get repo download information:\n%1").arg(error.toString());
+
+    seafApplet->warningBox(msg, this);
+
+    setAllInputsEnabled(true);
+}
+
+void DownloadRepoDialog::setMergeWithExisting(const QString& localPath) {
+    merge_without_question_ = true;
+    setDirectoryText(localPath);
+}
+
+void DownloadRepoDialog::setResyncMode() {
+    resync_mode_ = true;
+    setAllInputsEnabled(false);
+}
diff --git a/src/ui/download-repo-dialog.h b/src/ui/download-repo-dialog.h
new file mode 100644 (file)
index 0000000..2468dd3
--- /dev/null
@@ -0,0 +1,59 @@
+#include <QDialog>
+#include <QUrl>
+#include <QString>
+
+#include "account.h"
+#include "ui_download-repo-dialog.h"
+#include "api/server-repo.h"
+
+class RepoDownloadInfo;
+class ApiError;
+
+class DownloadRepoDialog : public QDialog,
+                           public Ui::DownloadRepoDialog
+{
+    Q_OBJECT
+public:
+    DownloadRepoDialog(const Account& account,
+                       const ServerRepo& repo,
+                       const QString& password,
+                       QWidget *parent=0);
+
+    void setMergeWithExisting(const QString& localPath);
+    void setResyncMode();
+
+private slots:
+    void onOkBtnClicked();
+    void chooseDirAction();
+    void onDownloadRepoRequestSuccess(const RepoDownloadInfo& info);
+    void onDownloadRepoRequestFailed(const ApiError& error);
+    void switchMode();
+    void startResync();
+
+private:
+    Q_DISABLE_COPY(DownloadRepoDialog);
+
+    bool validateInputDirectory();
+    bool validateInputs();
+    void setAllInputsEnabled(bool enabled);
+    void setDirectoryText(const QString& path);
+    void updateSyncMode();
+
+    ServerRepo repo_;
+    Account account_;
+
+    // if we are in manual merge mode
+    bool manual_merge_mode_;
+    // used in auto mode, and always true in manual merge mode
+    bool sync_with_existing_;
+
+    // merge without question
+    bool merge_without_question_;
+
+    // save merge path
+    QString alternative_path_;
+
+    // Set to true when the dialog is used to resync a library, i.e. no user
+    // interaction needed.
+    bool resync_mode_;
+};
diff --git a/src/ui/event-details-dialog.cpp b/src/ui/event-details-dialog.cpp
new file mode 100644 (file)
index 0000000..5a0b353
--- /dev/null
@@ -0,0 +1,102 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QVBoxLayout>
+#include <QStackedLayout>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "loading-view.h"
+#include "api/requests.h"
+#include "api/api-error.h"
+#include "api/commit-details.h"
+#include "event-details-tree.h"
+#include "repo-service.h"
+#include "set-repo-password-dialog.h"
+
+#include "event-details-dialog.h"
+
+namespace {
+
+enum {
+    INDEX_LOADING_VIEW = 0,
+    INDEX_DETAILS_VIEW,
+};
+
+} // namespace
+
+EventDetailsDialog::EventDetailsDialog(const SeafEvent& event, QWidget *parent)
+    : QDialog(parent),
+      event_(event)
+{
+    setWindowTitle(tr("Modification Details"));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    QStackedLayout *layout = new QStackedLayout;
+    layout->setContentsMargins(0, 0, 0, 0);
+    setLayout(layout);
+
+    loading_view_ = new LoadingView;
+    layout->addWidget(loading_view_);
+
+    tree_ = new EventDetailsListView(event);
+    model_ = new EventDetailsListModel(event);
+    tree_->setModel(model_);
+
+    layout->addWidget(tree_);
+
+    request_ = 0;
+
+    sendRequest();
+}
+
+void EventDetailsDialog::sendRequest()
+{
+    const Account& account = seafApplet->accountManager()->currentAccount();
+
+    if (request_) {
+        request_->deleteLater();
+    }
+
+    request_ = new GetCommitDetailsRequest(account, event_.repo_id, event_.commit_id);
+    connect(request_, SIGNAL(success(const CommitDetails&)),
+            this, SLOT(updateContent(const CommitDetails&)));
+    connect(request_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(getCommitDetailsFailed(const ApiError&)));
+    request_->send();
+}
+
+void EventDetailsDialog::updateContent(const CommitDetails& details)
+{
+    QStackedLayout *layout = (QStackedLayout *)this->layout();
+    layout->setCurrentIndex(INDEX_DETAILS_VIEW);
+
+    model_->setCommitDetails(details);
+}
+
+void EventDetailsDialog::getCommitDetailsFailed(const ApiError& error)
+{
+    ServerRepo repo = RepoService::instance()->getRepo(event_.repo_id);
+
+    if (!repo.isValid()) {
+        return;
+    }
+
+    if (repo.encrypted &&
+        error.type() == ApiError::HTTP_ERROR &&
+        error.httpErrorCode() == 400) {
+
+        SetRepoPasswordDialog dialog(repo, this);
+
+        if (dialog.exec() == QDialog::Accepted) {
+            sendRequest();
+        } else {
+            reject();
+        }
+    }
+}
diff --git a/src/ui/event-details-dialog.h b/src/ui/event-details-dialog.h
new file mode 100644 (file)
index 0000000..841cc30
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SEAFILE_CLIENT_UI_EVENT_DETAILS_DIALOG_H
+#define SEAFILE_CLIENT_UI_EVENT_DETAILS_DIALOG_H
+
+#include <QDialog>
+#include "api/event.h"
+
+class GetCommitDetailsRequest;
+class CommitDetails;
+class EventDetailsListView;
+class EventDetailsListModel;
+class ApiError;
+
+// Display the commit details in a simple tree view
+class EventDetailsDialog : public QDialog {
+    Q_OBJECT
+public:
+    EventDetailsDialog(const SeafEvent& event, QWidget *parent=0);
+
+private slots:
+    void updateContent(const CommitDetails& details);
+    void getCommitDetailsFailed(const ApiError& error);
+
+private:
+    Q_DISABLE_COPY(EventDetailsDialog)
+
+    void sendRequest();
+
+    SeafEvent event_;
+
+    GetCommitDetailsRequest *request_;
+
+    EventDetailsListView *tree_;
+    EventDetailsListModel *model_;
+    QWidget *loading_view_;
+};
+
+#endif // SEAFILE_CLIENT_UI_EVENT_DETAILS_DIALOG_H
diff --git a/src/ui/event-details-tree.cpp b/src/ui/event-details-tree.cpp
new file mode 100644 (file)
index 0000000..5721c9d
--- /dev/null
@@ -0,0 +1,320 @@
+#include <QtGlobal>
+#include <QFileInfo>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include "QtAwesome.h"
+
+#include "utils/file-utils.h"
+#include "utils/paint-utils.h"
+#include "repo-service.h"
+
+#include "event-details-tree.h"
+namespace {
+const int kMarginLeft = 10;
+const int kMarginRight = 10;
+const int kPadding = 5;
+const int kFileIconHeight = 12;
+const int kFileItemHeight = 30;
+const int kFileItemWidth = 300;
+
+const int kFileNameWidth = 260;
+
+const int kFileNameFontSize = 14;
+
+const char *kFileItemBackgroundColor = "white";
+const char *kFileItemBackgroundColorHighlighted = "#F9E0C7";
+} // anonymous namespace
+
+/**
+ *
+ *  status-icon file-path         status-text
+ */
+
+void EventDetailsFileItemDelegate::paint(QPainter *painter,
+                                         const QStyleOptionViewItem &option,
+                                         const QModelIndex &index) const {
+    QBrush backBrush;
+    bool selected = false;
+
+    if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) {
+        backBrush = QColor(kFileItemBackgroundColorHighlighted);
+        selected = true;
+
+    } else {
+        backBrush = QColor(kFileItemBackgroundColor);
+    }
+
+    painter->save();
+    painter->fillRect(option.rect, backBrush);
+    painter->restore();
+
+    if (!index.isValid())
+        return;
+
+    const EventDetailsListModel* model = static_cast<const EventDetailsListModel*>(index.model());
+    EventDetailsFileItem *item = static_cast<EventDetailsFileItem*>(model->item(index.row()));
+
+    const int height = option.rect.height();
+    // get the device pixel radio from current painter device
+    int scale_factor = 1;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    scale_factor = globalDevicePixelRatio();
+#endif // QT5
+    QPixmap icon(item->etype_icon().pixmap(QSize(kFileIconHeight, kFileIconHeight) * scale_factor).scaledToHeight(kFileIconHeight * scale_factor));
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    icon.setDevicePixelRatio(scale_factor);
+#endif // QT5
+    //
+    // draw status-icon
+    //
+
+    QPoint status_icon_pos = option.rect.topLeft() + QPoint(kMarginLeft, height / 2 - kFileIconHeight / 2);
+    painter->save();
+    painter->drawPixmap(status_icon_pos, icon);
+    painter->restore();
+
+    //
+    // draw file-path
+    //
+    const int file_path_width = static_cast<QWidget*>(parent())->width() - kFileItemWidth + kFileNameWidth;
+    QString path = item->path();
+    if (item->etype() == EventDetailsFileItem::FILE_RENAMED)
+        path = item->original_path() + " -> " + item->path();
+    painter->save();
+    QPoint file_name_pos = option.rect.topLeft() + QPoint(kMarginLeft + kFileIconHeight + kPadding, 0);
+    QRect file_name_rect(file_name_pos, QSize(file_path_width, height));
+    painter->setPen(QColor(item->etype_color()));
+    painter->setFont(changeFontSize(painter->font(), kFileNameFontSize));
+
+    painter->drawText(file_name_rect,
+                      Qt::AlignLeft | Qt::AlignVCenter,
+                      fitTextToWidth(path, option.font, file_path_width),
+                      &file_name_rect);
+    painter->restore();
+}
+
+QSize EventDetailsFileItemDelegate::sizeHint(const QStyleOptionViewItem &option,
+                                             const QModelIndex &index) const {
+    if (!index.isValid())
+        return QStyledItemDelegate::sizeHint(option, index);
+
+    return QSize(kFileItemWidth, kFileItemHeight);
+}
+
+EventDetailsFileItem::EventDetailsFileItem(const QString& path, EType etype, const QString& original_path)
+    : path_(path),
+      original_path_(original_path),
+      etype_(etype)
+{
+    // setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+    setEditable(false);
+}
+
+QString EventDetailsFileItem::name() const
+{
+    return path_;
+}
+
+QString EventDetailsFileItem::etype_desc() const
+{
+    switch(etype_) {
+      case FILE_ADDED:
+        return QObject::tr("Added");
+      case FILE_DELETED:
+        return QObject::tr("Deleted");
+      case FILE_MODIFIED:
+        return QObject::tr("Modified");
+      case FILE_RENAMED:
+        return QObject::tr("Renamed");
+      case DIR_ADDED:
+        return QObject::tr("Added");
+      case DIR_DELETED:
+        return QObject::tr("Deleted");
+    };
+}
+
+QIcon EventDetailsFileItem::etype_icon() const
+{
+    switch(etype_) {
+      case FILE_ADDED:
+        return awesome->icon(icon_plus, QColor("#6CC644"));
+      case FILE_DELETED:
+        return awesome->icon(icon_minus, QColor("#BD2C00"));
+      case FILE_MODIFIED:
+        return awesome->icon(icon_pencil, QColor("#D0B44C"));
+      case FILE_RENAMED:
+        return awesome->icon(icon_arrow_right, QColor("#677A85"));
+      case DIR_ADDED:
+        return awesome->icon(icon_plus, QColor("#6CC644"));
+      case DIR_DELETED:
+        return awesome->icon(icon_minus, QColor("#BD2C00"));
+    };
+}
+
+const char* EventDetailsFileItem::etype_color() const
+{
+    switch(etype_) {
+      case FILE_ADDED:
+        return "#6CC644";
+      case FILE_DELETED:
+        return "#BD2C00";
+      case FILE_MODIFIED:
+        return "#D0B44C";
+      case FILE_RENAMED:
+        return "#677A85";
+      case DIR_ADDED:
+        return "#6CC644";
+      case DIR_DELETED:
+        return "#BD2C00";
+    };
+}
+
+bool EventDetailsFileItem::isFileOpenable() const
+{
+    return etype_ == FILE_ADDED ||
+        etype_ == FILE_MODIFIED ||
+        etype_ == FILE_RENAMED ||
+        etype_ == DIR_ADDED;
+}
+
+QVariant EventDetailsFileItem::data(int role) const
+{
+    if (role == Qt::DecorationRole) {
+        if (etype_ == DIR_ADDED || etype_ == DIR_DELETED) {
+            return QIcon(":/images/folder.png");
+        }
+        return QIcon(::getIconByFileName(name()));
+    } else if (role == Qt::DisplayRole) {
+        return name();
+    } else if (role == Qt::ToolTipRole) {
+        return path_;
+    } else {
+        return QVariant();
+    }
+}
+
+
+EventDetailsListView::EventDetailsListView(const SeafEvent& event, QWidget *parent)
+    : QListView(parent),
+      event_(event)
+{
+#if defined(Q_OS_MAC)
+    this->setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+
+    setItemDelegate(new EventDetailsFileItemDelegate(this));
+
+    setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+    connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+            this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+
+    context_menu_ = new QMenu(this);
+    open_action_ = new QAction(tr("&Open"), this);
+    connect(open_action_, SIGNAL(triggered()),
+            this, SLOT(onOpen()));
+
+    open_in_file_browser_action_ = new QAction(tr("Open &parent folder"), this);
+    connect(open_in_file_browser_action_, SIGNAL(triggered()),
+            this, SLOT(onOpenInFileBrowser()));
+
+    context_menu_->addAction(open_action_);
+    context_menu_->addAction(open_in_file_browser_action_);
+}
+
+void EventDetailsListView::onItemDoubleClicked(const QModelIndex& index)
+{
+    QStandardItem *qitem = getFileItem(index);
+    if (!qitem) {
+        return;
+    }
+    EventDetailsFileItem *item = (EventDetailsFileItem *)qitem;
+    if (item->isFileOpenable()) {
+        RepoService::instance()->openLocalFile(event_.repo_id, item->path());
+    }
+}
+
+void EventDetailsListView::onOpen()
+{
+    if (!item_in_action_)
+        return;
+    RepoService::instance()->openLocalFile(event_.repo_id, item_in_action_->path());
+}
+
+void EventDetailsListView::onOpenInFileBrowser()
+{
+    if (!item_in_action_)
+        return;
+    RepoService::instance()->openFolder(event_.repo_id, QFileInfo(item_in_action_->path()).dir().path());
+}
+
+void EventDetailsListView::contextMenuEvent(QContextMenuEvent *event)
+{
+    QPoint position = event->pos();
+    const QModelIndex index = indexAt(position);
+    position = viewport()->mapToGlobal(position);
+
+    if (!index.isValid()) {
+        return;
+    }
+
+    const EventDetailsListModel* list_model = static_cast<EventDetailsListModel*>(model());
+    item_in_action_ = static_cast<EventDetailsFileItem*>(list_model->item(index.row()));
+    open_action_->setEnabled(item_in_action_->isFileOpenable());
+
+    context_menu_->exec(position); // synchronously
+}
+
+QStandardItem* EventDetailsListView::getFileItem(const QModelIndex& index)
+{
+    if (!index.isValid()) {
+        return NULL;
+    }
+    const EventDetailsListModel *model = (const EventDetailsListModel*)index.model();
+    QStandardItem *item = model->itemFromIndex(index);
+    return item;
+}
+
+EventDetailsListModel::EventDetailsListModel(const SeafEvent& event, QObject *parent)
+    : QStandardItemModel(parent),
+      event_(event)
+{
+}
+
+void EventDetailsListModel::setCommitDetails(const CommitDetails& details)
+{
+    clear();
+
+    details_ = details;
+
+    processEventCategory(details.added_files, tr("Added files"),  EventDetailsFileItem::FILE_ADDED);
+    processEventCategory(details.deleted_files, tr("Deleted files"),  EventDetailsFileItem::FILE_DELETED);
+    processEventCategory(details.modified_files, tr("Modified files"),  EventDetailsFileItem::FILE_MODIFIED);
+
+    processEventCategory(details.added_dirs, tr("Added folders"),  EventDetailsFileItem::DIR_ADDED);
+    processEventCategory(details.deleted_dirs, tr("Deleted folders"),  EventDetailsFileItem::DIR_DELETED);
+
+    // renamed files is a list of (before rename, after rename) pair
+    for (int i = 0, n = details.renamed_files.size(); i < n; i++) {
+        EventDetailsFileItem *item = new EventDetailsFileItem(details.renamed_files[i].second, EventDetailsFileItem::FILE_RENAMED, details.renamed_files[i].first);
+        appendRow(item);
+    }
+}
+
+void EventDetailsListModel::processEventCategory(const std::vector<QString>& files,
+                                                 const QString& desc,
+                                                 EventDetailsFileItem::EType etype)
+{
+    if (files.empty()) {
+        return;
+    }
+
+    for (int i = 0, n = files.size(); i < n; i++) {
+        EventDetailsFileItem *item = new EventDetailsFileItem(files[i], etype);
+        appendRow(item);
+    }
+}
diff --git a/src/ui/event-details-tree.h b/src/ui/event-details-tree.h
new file mode 100644 (file)
index 0000000..ca57b61
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef SEAFILE_CLIENT_UI_EVENT_DETAILS_TREE_H
+#define SEAFILE_CLIENT_UI_EVENT_DETAILS_TREE_H
+
+#include <QListView>
+#include <QStandardItemModel>
+#include <QStandardItem>
+#include <QStyledItemDelegate>
+#include <QIcon>
+
+#include "api/event.h"
+#include "api/commit-details.h"
+
+class QModelIndex;
+class QMenu;
+
+class EventDetailsFileItem : public QStandardItem {
+public:
+    enum EType {
+        FILE_ADDED = 0,
+        FILE_DELETED,
+        FILE_MODIFIED,
+        FILE_RENAMED,
+        DIR_ADDED,
+        DIR_DELETED
+    };
+
+    EventDetailsFileItem(const QString& path, EType etype, const QString& original_path = "");
+
+    virtual QVariant data(int role) const;
+
+    bool isFileOpenable() const;
+
+    // accessors
+    QString name() const;
+    const QString& path() const { return path_; }
+    const QString& original_path() const { return original_path_; }
+    EType etype() const { return etype_; }
+    QString etype_desc() const;
+    QIcon etype_icon() const;
+    const char* etype_color() const;
+
+private:
+
+    QString path_;
+    QString original_path_;
+    EType etype_;
+};
+
+class EventDetailsListView : public QListView {
+    Q_OBJECT
+public:
+    EventDetailsListView(const SeafEvent& event, QWidget *parent=0);
+
+private slots:
+    void onItemDoubleClicked(const QModelIndex& index);
+    void onOpen();
+    void onOpenInFileBrowser();
+
+private:
+    QStandardItem* getFileItem(const QModelIndex& index);
+
+    void contextMenuEvent(QContextMenuEvent * event);
+
+    SeafEvent event_;
+    QMenu* context_menu_;
+    QAction* open_action_;
+    QAction* open_in_file_browser_action_;
+    EventDetailsFileItem* item_in_action_;
+};
+
+class EventDetailsListModel : public QStandardItemModel {
+    Q_OBJECT
+public:
+    EventDetailsListModel(const SeafEvent& event, QObject *parent=0);
+
+    void setCommitDetails(const CommitDetails& details);
+
+private:
+    void processEventCategory(const std::vector<QString>& files,
+                              const QString& desc,
+                              EventDetailsFileItem::EType etype);
+
+    SeafEvent event_;
+    CommitDetails details_;
+};
+
+class EventDetailsFileItemDelegate : public QStyledItemDelegate {
+    Q_OBJECT
+public:
+    explicit EventDetailsFileItemDelegate(QWidget *parent)
+        : QStyledItemDelegate(parent) {}
+    void paint(QPainter *painter,
+               const QStyleOptionViewItem& option,
+               const QModelIndex& index) const;
+
+    QSize sizeHint(const QStyleOptionViewItem& option,
+                   const QModelIndex& index) const;
+};
+
+#endif // SEAFILE_CLIENT_UI_EVENT_DETAILS_TREE_H
diff --git a/src/ui/events-list-view.cpp b/src/ui/events-list-view.cpp
new file mode 100644 (file)
index 0000000..b1d04ab
--- /dev/null
@@ -0,0 +1,460 @@
+#include <QPainter>
+#include <QApplication>
+#include <QPixmap>
+#include <QToolTip>
+#include <QLayout>
+#include <QDebug>
+
+#include "seafile-applet.h"
+#include "main-window.h"
+#include "events-service.h"
+#include "avatar-service.h"
+#include "event-details-dialog.h"
+#include "utils/paint-utils.h"
+#include "utils/utils.h"
+#include "api/event.h"
+
+#include "events-list-view.h"
+
+namespace {
+
+// new file activities ui
+/**
+         nick    operation     date
+   icon
+         description  repo name
+ */
+
+/**
+         nick         date
+   icon
+         description  repo name
+ */
+
+const int kMarginLeft = 5;
+const int kMarginRight = 5;
+const int kMarginTop = 5;
+const int kMarginBottom = 5;
+const int kPadding = 5;
+#ifdef Q_OS_MAC
+const int kExtraPadding = 5;
+#else
+const int kExtraPadding = 0;
+#endif
+
+const int kAvatarHeight = 40;
+const int kAvatarWidth = 40;
+//const int kNickWidth = 210;
+const int kNickHeight = 30;
+const int kOperationHeight = 18;
+const qreal kRadius = 3;
+
+const int kMarginBetweenAvatarAndNick = 10;
+const int kMarginBetweenNickAndOperation = 10;
+const int kVerticalMarginBetweenNickAndDesc = 3;
+
+const char *kNickColor = "#D8AC8F";
+const char *kNickColorHighlighted = "#D8AC8F";
+const char *kOperationColor = "white";
+const char *kOperRectFillColor = "#D8AC8F";
+const char *kRepoNameColor = "#D8AC8F";
+const char *kRepoNameColorHighlighted = "#D8AC8F";
+const char *kDescriptionColor = "#3F3F3F";
+const char *kDescriptionColorHighlighted = "#544D49";
+
+const int kNickFontSize = 16;
+const int kOperationFontSize = 13;
+const int kDescriptionFontSize = 13;
+const int kDescriptionHeight = 30;
+
+const char *kEventItemBackgroundColor = "white";
+const char *kEventItemBackgroundColorHighlighted = "#F9E0C7";
+
+const int kTimeWidth = 100;
+const int kTimeHeight = 30;
+const int kTimeFontSize = 13;
+
+const int kRepoNameWidth = 80;
+
+const char *kTimeColor = "#959595";
+const char *kTimeColorHighlighted = "#9D9B9A";
+
+const int kMarginBetweenNickAndTime = 10;
+const int kMarginBetweenOperationAndTime = 10;
+
+const int kMarginBetweenRepoNameAndDesc = 10;
+
+
+const char *kItemBottomBorderColor = "#EEE";
+
+} // namespace
+
+
+
+EventItem::EventItem(const SeafEvent& event)
+    : event_(event)
+{
+}
+
+EventItemDelegate::EventItemDelegate(QObject *parent)
+    : QStyledItemDelegate(parent)
+{
+}
+
+void EventItemDelegate::paint(QPainter *painter,
+                              const QStyleOptionViewItem& option,
+                              const QModelIndex& index) const
+{
+    QBrush backBrush;
+    bool selected = false;
+
+    EventItem *item = getItem(index);
+    if (!item) {
+        return;
+    }
+
+    const SeafEvent& event = item->event();
+    QString operation_text = event.op_desc;
+    QString time_text = translateCommitTime(event.timestamp);
+
+    if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) {
+        backBrush = QColor(kEventItemBackgroundColorHighlighted);
+        selected = true;
+
+    } else {
+        backBrush = QColor(kEventItemBackgroundColor);
+    }
+
+    painter->save();
+    painter->fillRect(option.rect, backBrush);
+    painter->restore();
+    painter->setRenderHint(QPainter::Antialiasing);
+    painter->setRenderHint(QPainter::HighQualityAntialiasing);
+
+    // get the device pixel radio from current painter device
+    double scale_factor = 1;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    scale_factor = globalDevicePixelRatio();
+#endif // QT5
+
+    // paint avatar
+    QImage avatar;
+    if (!event.anonymous) {
+        avatar = AvatarService::instance()->getAvatar(event.author);
+    }
+
+    QRect actualRect(0, 0, kAvatarWidth * scale_factor , kAvatarHeight * scale_factor);
+    avatar.scaled(actualRect.size());
+    QImage masked_image(actualRect.size(), QImage::Format_ARGB32_Premultiplied);
+    masked_image.fill(Qt::transparent);
+    QPainter mask_painter;
+    mask_painter.begin(&masked_image);
+    mask_painter.setRenderHint(QPainter::Antialiasing);
+    mask_painter.setRenderHint(QPainter::HighQualityAntialiasing);
+    mask_painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+    mask_painter.setPen(Qt::NoPen);
+    mask_painter.setBrush(Qt::white);
+    mask_painter.drawEllipse(actualRect);
+    mask_painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+    mask_painter.drawImage(actualRect, avatar);
+    mask_painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
+    mask_painter.fillRect(actualRect, Qt::transparent);
+    mask_painter.end();
+    masked_image.setDevicePixelRatio(scale_factor);
+
+    QPoint avatar_pos(kMarginLeft + kPadding, kMarginTop + kPadding);
+    avatar_pos += option.rect.topLeft();
+    painter->save();
+    painter->drawImage(avatar_pos, masked_image);
+    painter->restore();
+
+    auto time_font = changeFontSize(painter->font(), kTimeFontSize);
+    auto nick_font = changeFontSize(painter->font(), kNickFontSize);
+    auto operation_font = changeFontSize(painter->font(), kOperationFontSize);
+    auto desc_font = changeFontSize(painter->font(), kDescriptionFontSize);
+    auto repo_name_font = time_font;
+
+    const int operation_width = ::textWidthInFont(operation_text, operation_font);
+    const int time_width = qMin(kTimeWidth, ::textWidthInFont(time_text, time_font));
+
+    int nick_width;
+    if (event.is_use_new_activities_api) {
+        nick_width = option.rect.width() - kMarginLeft - kAvatarWidth - kMarginBetweenAvatarAndNick
+            - kMarginBetweenNickAndOperation - operation_width - kMarginBetweenOperationAndTime
+            - time_width - kPadding * 2 - kMarginRight;
+    } else {
+        nick_width = option.rect.width() - kMarginLeft - kAvatarWidth - kMarginBetweenAvatarAndNick
+            - time_width - kMarginBetweenNickAndTime - kPadding * 2 - kMarginRight;
+    }
+
+    nick_width = qMin(nick_width, ::textWidthInFont(event.nick, nick_font));
+
+    // Paint nick name
+    QPoint nick_pos = avatar_pos + QPoint(kAvatarWidth + kMarginBetweenAvatarAndNick, 0);
+    QRect nick_rect(nick_pos, QSize(nick_width, kNickHeight));
+    painter->save();
+    painter->setPen(QColor(selected ? kNickColorHighlighted : kNickColor));
+    painter->setFont(nick_font);
+    painter->drawText(nick_rect,
+                      Qt::AlignLeft | Qt::AlignTop,
+                      fitTextToWidth(event.nick, option.font, nick_width),
+                      &nick_rect);
+    painter->restore();
+
+    // Paint operation name
+    if (event.is_use_new_activities_api) {
+        QPoint operation_pos = nick_pos + QPoint(nick_width + kMarginBetweenNickAndOperation, 3);
+        QRect operation_rect(operation_pos, QSize(operation_width + 8, kOperationHeight));
+        painter->save();
+        QPainterPath path;
+        path.addRoundedRect(operation_rect, kRadius, kRadius);
+        painter->fillPath(path, QColor(kOperRectFillColor));
+
+        painter->setPen(QColor(kOperationColor));
+        painter->setFont(operation_font);
+        painter->drawText(operation_rect,
+                    Qt::AlignCenter,
+                    fitTextToWidth(operation_text, option.font, operation_width),
+                    &operation_rect);
+        painter->restore();
+    }
+
+    // Paint event time
+    painter->save();
+    QPoint time_pos = option.rect.topRight() + QPoint(-time_width - kPadding - kMarginRight, kMarginTop + kPadding);
+    QRect time_rect(time_pos, QSize(time_width, kTimeHeight));
+    painter->setPen(QColor(selected ? kTimeColorHighlighted : kTimeColor));
+    painter->setFont(time_font);
+
+    painter->drawText(time_rect,
+                      Qt::AlignRight | Qt::AlignTop,
+                      time_text,
+                      &time_rect);
+    painter->restore();
+
+    // Paint description
+    painter->save();
+
+    QString desc = event.desc;
+
+    int repo_name_width = qMin(kRepoNameWidth, ::textWidthInFont(event.repo_name, repo_name_font));
+
+    int desc_width = option.rect.width() - kMarginLeft - kAvatarWidth -
+                     kMarginBetweenAvatarAndNick -
+                     kMarginBetweenRepoNameAndDesc - repo_name_width -
+                     kMarginRight - kPadding * 2;
+
+    const int desc_height = ::textHeightInFont(desc, desc_font) * 2;
+
+    // const QPoint event_desc_pos = option.rect.bottomLeft() + QPoint(nick_rect.left(), - desc_height - kExtraPadding - kMarginBottom);
+    const QPoint event_desc_pos = nick_rect.bottomLeft() + QPoint(0, kVerticalMarginBetweenNickAndDesc);
+
+    QRect event_desc_rect(event_desc_pos, QSize(desc_width, desc_height));
+    painter->setFont(desc_font);
+    painter->setPen(QColor(selected ? kDescriptionColorHighlighted : kDescriptionColor));
+
+    desc.replace(QChar('\n'), QChar(' '));
+    painter->drawText(event_desc_rect,
+                      Qt::AlignLeft | Qt::AlignTop | Qt::TextWrapAnywhere,
+                      // we have two lines
+                      fitTextToWidth(desc, desc_font, desc_width * 2),
+                      &event_desc_rect);
+    painter->restore();
+
+    // Paint repo name
+    painter->save();
+
+    repo_name_width += desc_width - event_desc_rect.width();
+    // if (index.row() == 1) {
+    //     printf ("width diff = %d\n", desc_width - event_desc_rect.width());
+    // }
+
+    const int repo_name_height = ::textHeightInFont(event.repo_name, repo_name_font);
+    const QPoint event_repo_name_pos = option.rect.bottomRight() +
+        QPoint(-repo_name_width - kPadding - kMarginRight,
+               -repo_name_height - kExtraPadding - kMarginBottom);
+
+    QRect event_repo_name_rect(event_repo_name_pos, QSize(repo_name_width, kNickHeight));
+    painter->setFont(repo_name_font);
+    painter->setPen(QColor(selected ? kRepoNameColorHighlighted : kRepoNameColor));
+    painter->drawText(
+        event_repo_name_rect,
+        Qt::AlignRight | Qt::AlignTop | Qt::TextSingleLine,
+        fitTextToWidth(event.repo_name, repo_name_font, repo_name_width),
+        &event_repo_name_rect);
+    painter->restore();
+
+    // const EventsListModel *model = (const EventsListModel*)index.model();
+    //
+    // Draw the bottom border lines except for the last item (if the "load more" is present")
+    // We minus 2 here becase:
+    // 1) the row index starts from 0
+    // 2) we addded a row for the "load more" data in the end
+    // if (model->loadMoreIndex().isValid() && index.row() == model->rowCount() - 2) {
+    //     return;
+    // }
+
+    painter->save();
+    painter->setPen(QPen(QColor(kItemBottomBorderColor), 1, Qt::SolidLine));
+    QPoint left = option.rect.bottomLeft();
+    left.setY(left.y() + 1);
+    QPoint right = option.rect.bottomRight();
+    right.setY(right.y() + 1);
+    painter->drawLine(left, right);
+    painter->restore();
+}
+
+QSize EventItemDelegate::sizeHint(const QStyleOptionViewItem& option,
+                                  const QModelIndex& index) const
+{
+    int height = kNickHeight + kDescriptionHeight + kPadding * 4 - kExtraPadding;
+    return QSize(option.rect.width(), height);
+}
+
+EventItem*
+EventItemDelegate::getItem(const QModelIndex &index) const
+{
+    if (!index.isValid()) {
+        return NULL;
+    }
+    const EventsListModel *model = (const EventsListModel*)index.model();
+    QStandardItem *qitem = model->itemFromIndex(index);
+    if (qitem->type() == EVENT_ITEM_TYPE) {
+        return (EventItem *)qitem;
+    } else {
+        return NULL;
+    }
+}
+
+EventsListView::EventsListView(QWidget *parent)
+    : QListView(parent)
+{
+    setItemDelegate(new EventItemDelegate);
+    connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+            this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+
+    setEditTriggers(QAbstractItemView::NoEditTriggers);
+}
+
+EventItem*
+EventsListView::getItem(const QModelIndex &index) const
+{
+    if (!index.isValid()) {
+        return NULL;
+    }
+    const EventsListModel *model = (const EventsListModel*)index.model();
+    QStandardItem *qitem = model->itemFromIndex(index);
+    if (qitem->type() == EVENT_ITEM_TYPE) {
+        return (EventItem *)qitem;
+    }
+    return NULL;
+}
+
+void EventsListView::onItemDoubleClicked(const QModelIndex& index)
+{
+    EventItem *item = getItem(index);
+    if (!item) {
+        return;
+    }
+
+    const SeafEvent& event = item->event();
+
+    if (!event.isDetailsDisplayable()) {
+        return;
+    }
+
+    EventDetailsDialog* dialog = new EventDetailsDialog(event, seafApplet->mainWindow());
+    dialog->setAttribute(Qt::WA_DeleteOnClose, true);
+    dialog->show();
+    dialog->raise();
+    dialog->activateWindow();
+}
+
+bool EventsListView::viewportEvent(QEvent *event)
+{
+    if (event->type() != QEvent::ToolTip && event->type() != QEvent::WhatsThis) {
+        return QListView::viewportEvent(event);
+    }
+
+    QPoint global_pos = QCursor::pos();
+    QPoint viewport_pos = viewport()->mapFromGlobal(global_pos);
+    QModelIndex index = indexAt(viewport_pos);
+    if (!index.isValid()) {
+        return true;
+    }
+
+    EventItem *item = getItem(index);
+    if (!item) {
+        return true;
+    }
+
+    QRect item_rect = visualRect(index);
+
+    QString text = "<p style='white-space:pre'>";
+    text += item->event().desc;
+    text += "</p>";
+
+    QToolTip::showText(QCursor::pos(), text, viewport(), item_rect);
+
+    return true;
+}
+
+
+EventsListModel::EventsListModel(QObject *parent)
+    : QStandardItemModel(parent)
+{
+}
+
+const QModelIndex
+EventsListModel::updateEvents(const std::vector<SeafEvent>& events,
+                              bool is_loading_more,
+                              bool has_more)
+{
+    if (!is_loading_more) {
+        clear();
+    }
+    int i = 0, n = events.size();
+
+    EventItem *first_item = 0;
+
+    for (i = 0; i < n; i++) {
+        SeafEvent event = events[i];
+        EventItem *item = new EventItem(event);
+
+        appendRow(item);
+
+        if (!first_item) {
+            first_item = item;
+        }
+    }
+
+    if (has_more) {
+        QStandardItem *load_more_item = new QStandardItem();
+        appendRow(load_more_item);
+        load_more_index_ = load_more_item->index();
+    }
+
+    if (is_loading_more && first_item) {
+        return indexFromItem(first_item);
+    }
+
+    return QModelIndex();
+}
+
+void EventsListModel::onAvatarUpdated(const QString& email, const QImage& img)
+{
+    int i, n = rowCount();
+
+    for (i = 0; i < n; i++) {
+        QStandardItem *qitem = item(i);
+        if (qitem->type() != EVENT_ITEM_TYPE) {
+            return;
+        }
+        EventItem *item = (EventItem *)qitem;
+
+        if (item->event().author == email) {
+            QModelIndex index = indexFromItem(item);
+            emit dataChanged(index, index);
+        }
+    }
+}
diff --git a/src/ui/events-list-view.h b/src/ui/events-list-view.h
new file mode 100644 (file)
index 0000000..a3dfcd2
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef SEAFILE_CLIENT_UI_EVENTS_LIST_VIEW_H
+#define SEAFILE_CLIENT_UI_EVENTS_LIST_VIEW_H
+
+#include <vector>
+#include <QListView>
+#include <QStandardItem>
+#include <QStyledItemDelegate>
+#include <QModelIndex>
+
+#include "api/event.h"
+
+class QImage;
+class QEvent;
+
+class SeafEvent;
+
+enum {
+    EVENT_ITEM_TYPE = QStandardItem::UserType,
+};
+
+class EventItem : public QStandardItem {
+public:
+    EventItem(const SeafEvent& event);
+
+    virtual int type() const { return EVENT_ITEM_TYPE; }
+
+    const SeafEvent& event() const { return event_; }
+
+private:
+
+    SeafEvent event_;
+};
+
+class EventItemDelegate : public QStyledItemDelegate {
+    Q_OBJECT
+public:
+    explicit EventItemDelegate(QObject *parent=0);
+
+    void paint(QPainter *painter,
+               const QStyleOptionViewItem& option,
+               const QModelIndex& index) const;
+
+    QSize sizeHint(const QStyleOptionViewItem& option,
+                   const QModelIndex& index) const;
+
+private:
+    void paintItem(QPainter *painter,
+                   const QStyleOptionViewItem& opt,
+                   const EventItem *item) const;
+
+    QSize sizeHintForItem(const QStyleOptionViewItem &option,
+                          const EventItem *item) const;
+
+    EventItem* getItem(const QModelIndex &index) const;
+};
+
+class EventsListModel : public QStandardItemModel {
+    Q_OBJECT
+public:
+    EventsListModel(QObject *parent=0);
+
+    const QModelIndex updateEvents(const std::vector<SeafEvent>& events,
+                                   bool is_loading_more,
+                                   bool has_more);
+    const QModelIndex loadMoreIndex() const { return load_more_index_; }
+
+public slots:
+    void onAvatarUpdated(const QString& email, const QImage& img);
+
+private:
+    QModelIndex load_more_index_;
+};
+
+class EventsListView : public QListView {
+    Q_OBJECT
+public:
+    EventsListView(QWidget *parent=0);
+
+    void updateEvents(const std::vector<SeafEvent>& events, bool is_loading_more);
+
+    bool viewportEvent(QEvent *event);
+                                                                                 
+private slots:
+    void onItemDoubleClicked(const QModelIndex& index);
+
+private:
+    Q_DISABLE_COPY(EventsListView)
+
+    EventItem* getItem(const QModelIndex &index) const;
+};
+
+
+#endif // SEAFILE_CLIENT_UI_EVENTS_LIST_VIEW_H
diff --git a/src/ui/init-seafile-dialog.cpp b/src/ui/init-seafile-dialog.cpp
new file mode 100644 (file)
index 0000000..a1de4ee
--- /dev/null
@@ -0,0 +1,216 @@
+#if !defined(Q_OS_WIN32)
+#include <sys/stat.h>
+#endif
+
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "init-seafile-dialog.h"
+#include <vector>
+
+#if defined(Q_OS_WIN32)
+#include <ShlObj.h>
+#include <shlwapi.h>
+#endif
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+QString get_largest_drive()
+{
+    wchar_t drives[MAX_PATH];
+    wchar_t *p, *largest_drive;
+    ULARGE_INTEGER free_space;
+    ULARGE_INTEGER largest_free_space;
+
+    largest_free_space.QuadPart = 0;
+    largest_drive = NULL;
+
+    GetLogicalDriveStringsW (sizeof(drives), drives);
+    for (p = drives; *p != L'\0'; p += wcslen(p) + 1) {
+        /* Skip floppy disk, network drive, etc */
+        if (GetDriveTypeW(p) != DRIVE_FIXED)
+            continue;
+
+        if (GetDiskFreeSpaceExW (p, &free_space, NULL, NULL)) {
+            if (free_space.QuadPart > largest_free_space.QuadPart) {
+                largest_free_space.QuadPart = free_space.QuadPart;
+                if (largest_drive != NULL) {
+                    free (largest_drive);
+                }
+                largest_drive = wcsdup(p);
+            }
+
+        } else {
+            qDebug ("failed to GetDiskFreeSpaceEx(), GLE=%lu\n",
+                    GetLastError());
+        }
+    }
+
+    QString ret;
+    if (largest_drive) {
+        ret = QString::fromStdWString(largest_drive);
+        free(largest_drive);
+    }
+
+    return ret;
+}
+
+QString getSystemDirectory()
+{
+    std::vector<wchar_t> path;
+    path.resize(MAX_PATH);
+
+    UINT len = ::GetSystemDirectoryW(&path[0], MAX_PATH);
+    path.resize(len);
+    if (len > MAX_PATH) {
+        len = ::GetSystemDirectoryW(&path[0], len);
+    }
+    return QString::fromWCharArray(&path[0], (int)len);
+}
+
+inline bool hasSameDrive(const QString& path_a, const QString &path_b)
+{
+    // to detect drive letter of a file, use QFileInfo::absoluteFilePath
+    //                                   (D:\)
+    // On Windows this will always begin 'D:/' where D is a drive letter, except
+    // for network shares that are not mapped to a drive letter
+    // same driver letter?
+    if (path_a.length() < 3 || path_b.length() < 3)
+        return false;
+    if (path_a[0] != path_b[0])
+        return false;
+    if (path_a[1] != ':' || (path_a[2] != '/' && path_a[2] != '\\') ||
+        path_b[1] != ':' || (path_b[2] != '/' && path_b[2] != '\\'))
+        return false;
+    return true;
+}
+
+#endif
+
+
+} // namespace
+
+InitSeafileDialog::InitSeafileDialog(QWidget *parent)
+    : QDialog(parent)
+{
+    setupUi(this);
+
+    setWindowTitle(tr("%1 Initialization").arg(getBrand()));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    connect(mChooseDirBtn, SIGNAL(clicked()), this, SLOT(chooseDir()));
+    connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkClicked()));
+    connect(mCancelBtn, SIGNAL(clicked()), this, SLOT(onCancelClicked()));
+
+    mTitle->setText(tr("Choose %1 folder").arg(getBrand()));
+    mCentralText->setText(
+        tr("Please choose a folder. We will create a %1 subfolder in it. "
+           "When you download a library, it will be saved there by default.")
+            .arg(getBrand()));
+    mLogo->setPixmap(QPixmap(":/images/seafile-32.png"));
+    mDirectory->setText(getInitialPath());
+
+    const QRect screen = QApplication::desktop()->screenGeometry();
+    move(screen.center() - this->rect().center());
+}
+
+QString InitSeafileDialog::getInitialPath()
+{
+#if defined(Q_OS_WIN32)
+    QString largest_drive = get_largest_drive();
+    QString home_path = QDir::home().absolutePath();
+    QString sys_path = getSystemDirectory();
+    if (hasSameDrive(largest_drive, sys_path) ||
+        hasSameDrive(largest_drive, home_path))
+        return home_path;
+
+    // work around with UTF-16 bug?
+    return QString::fromUtf8(largest_drive.toUtf8());
+#else
+    return QDir::home().path();
+#endif
+}
+
+void InitSeafileDialog::chooseDir()
+{
+    QString initial_path;
+
+    // On windows, set the initial path to the max volume, on linux/mac, set
+    // to the home direcotry.
+    QString dir = QFileDialog::getExistingDirectory(this, tr("Please choose a directory"),
+                                                    getInitialPath(),
+                                                    QFileDialog::ShowDirsOnly
+                                                    | QFileDialog::DontResolveSymlinks);
+    if (dir.isEmpty())
+        return;
+
+    mDirectory->setText(dir);
+}
+
+void InitSeafileDialog::onOkClicked()
+{
+    QString path = mDirectory->text();
+    if (path.isEmpty()) {
+        seafApplet->warningBox(tr("Please choose a directory"), this);
+        return;
+    }
+
+    QDir dir(path);
+    if (!dir.exists()) {
+        seafApplet->warningBox(tr("The folder %1 does not exist").arg(path), this);
+        return;
+    }
+
+#if defined(Q_OS_WIN32)
+    QString data_dir_name = QString("%1/seafile-data").arg(getBrand());
+#else
+    QString data_dir_name = QString("%1/.seafile-data").arg(getBrand());
+#endif
+
+    dir.mkpath(data_dir_name);
+    QString seafile_dir = dir.filePath(data_dir_name);
+
+    // the .seafile-data Directory has set "read" rights for "others".
+    // if this Directory is "stolen", an attacker can access all files 
+    // which are not in an encrypted file containe.
+#if !defined(Q_OS_WIN32)
+    int chmod_return_code = chmod(
+        toCStr(data_dir_name), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+    if (chmod_return_code < 0) {
+        qWarning("Modify the file \"%s\" permission error.",
+            toCStr(data_dir_name));
+    }
+#endif
+
+    emit seafileDirSet(seafile_dir);
+
+    accept();
+}
+
+void InitSeafileDialog::onCancelClicked()
+{
+    if (seafApplet->yesOrNoBox(
+            tr("Initialization is not finished. Really quit?"), this, false)) {
+        reject();
+    }
+}
+
+void InitSeafileDialog::closeEvent(QCloseEvent *event)
+{
+    if (seafApplet->yesOrNoBox(
+            tr("Initialization is not finished. Really quit?"), this, false)) {
+        QDialog::closeEvent(event);
+        return;
+    }
+    event->ignore();
+}
diff --git a/src/ui/init-seafile-dialog.h b/src/ui/init-seafile-dialog.h
new file mode 100644 (file)
index 0000000..84de15f
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef SEAFILE_CLIENT_INIT_SEAFILE_DIALOG_H
+#define SEAFILE_CLIENT_INIT_SEAFILE_DIALOG_H
+
+#include <QDialog>
+#include "ui_init-seafile-dialog.h"
+
+class QCloseEvent;
+
+class InitSeafileDialog : public QDialog,
+                          public Ui::InitSeafileDialog
+{
+    Q_OBJECT
+
+public:
+    InitSeafileDialog(QWidget *parent=0);
+    void closeEvent(QCloseEvent *event);
+
+private slots:
+    void onOkClicked();
+    void onCancelClicked();
+    void chooseDir();
+
+signals:
+    void seafileDirSet(const QString&);
+
+private:
+    QString getInitialPath();
+};
+
+#endif  // SEAFILE_CLIENT_INIT_SEAFILE_DIALOG_H
diff --git a/src/ui/init-vdrive-dialog.cpp b/src/ui/init-vdrive-dialog.cpp
new file mode 100644 (file)
index 0000000..491ef2f
--- /dev/null
@@ -0,0 +1,285 @@
+#include <cstdio>
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QTimer>
+#include <QPixmap>
+#include <QFile>
+#include <QFileInfo>
+#include <QCoreApplication>
+
+#include "seafile-applet.h"
+#include "utils/utils.h"
+#include "configurator.h"
+#include "settings-mgr.h"
+#include "api/requests.h"
+#include "api/api-error.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "rpc/clone-task.h"
+
+#include "init-vdrive-dialog.h"
+
+namespace {
+
+const int kCheckDownloadInterval = 2000;
+
+} // namespace
+
+
+InitVirtualDriveDialog::InitVirtualDriveDialog(const Account& account, QWidget *parent)
+    : QDialog(parent),
+      account_(account)
+{
+    setupUi(this);
+    mLogo->setPixmap(QPixmap(":/images/seafile-32.png"));
+    setWindowTitle(tr("Download Default Library"));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    mStatusText->setText(
+        tr("%1 organizes files by libraries.\nDo you like to download your "
+           "default library?").arg(getBrand()));
+    setStatusIcon(":/images/download-48.png");
+
+    create_default_repo_req_ = NULL;
+    download_default_repo_req_ = NULL;
+
+    check_download_timer_ = NULL;
+    connect(mYesBtn, SIGNAL(clicked()), this, SLOT(start()));
+    connect(mNoBtn, SIGNAL(clicked()), this, SLOT(onCancel()));
+
+    mRunInBackgroundBtn->setVisible(false);
+    mFinishBtn->setVisible(false);
+    mOpenBtn->setVisible(false);
+}
+
+void InitVirtualDriveDialog::start()
+{
+    // mYesBtn->setEnabled(false);
+    // mNoBtn->setEnabled(false);
+    mYesBtn->setVisible(false);
+    mNoBtn->setVisible(false);
+    getDefaultRepo();
+}
+
+void InitVirtualDriveDialog::onCancel()
+{
+    reject();
+}
+
+void InitVirtualDriveDialog::getDefaultRepo()
+{
+    setStatusText(tr("Checking your default library..."));
+    get_default_repo_req_ = new GetDefaultRepoRequest(account_);
+
+    connect(get_default_repo_req_, SIGNAL(success(bool, const QString&)),
+            this, SLOT(onGetDefaultRepoSuccess(bool, const QString&)));
+
+    connect(get_default_repo_req_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetDefaultRepoFailure(const ApiError&)));
+
+    get_default_repo_req_->send();
+}
+
+void InitVirtualDriveDialog::createDefaultRepo()
+{
+    setStatusText(tr("Creating the default library..."));
+    create_default_repo_req_ = new CreateDefaultRepoRequest(account_);
+
+    connect(create_default_repo_req_, SIGNAL(success(const QString&)),
+            this, SLOT(onCreateDefaultRepoSuccess(const QString&)));
+
+    connect(create_default_repo_req_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onCreateDefaultRepoFailure(const ApiError&)));
+
+    create_default_repo_req_->send();
+}
+
+void InitVirtualDriveDialog::startDownload(const QString& repo_id)
+{
+    default_repo_id_ = repo_id;
+
+    LocalRepo repo;
+
+    seafApplet->rpcClient()->getLocalRepo(repo_id, &repo);
+    if (repo.isValid()) {
+        // This repo is already here
+        qDebug("The default library has already been downloaded");
+        default_repo_path_ = repo.worktree;
+        finish();
+        return;
+    }
+
+    download_default_repo_req_ = new DownloadRepoRequest(account_, repo_id, false);
+
+    connect(download_default_repo_req_, SIGNAL(success(const RepoDownloadInfo&)),
+            this, SLOT(onDownloadRepoSuccess(const RepoDownloadInfo&)));
+
+    connect(download_default_repo_req_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onDownloadRepoFailure(const ApiError&)));
+
+    download_default_repo_req_->send();
+}
+
+void InitVirtualDriveDialog::onGetDefaultRepoSuccess(bool exists, const QString& repo_id)
+{
+    if (!exists) {
+        createDefaultRepo();
+    } else {
+        startDownload(repo_id);
+    }
+}
+
+void InitVirtualDriveDialog::onGetDefaultRepoFailure(const ApiError& error)
+{
+    if (error.type() == ApiError::HTTP_ERROR && error.httpErrorCode() == 404) {
+        fail(tr("Failed to create default library:\n\n"
+                "The server version must be 2.1 or higher to support this."));
+    } else {
+        fail(tr("Failed to get default library:\n%1").arg(error.toString()));
+    }
+}
+
+
+void InitVirtualDriveDialog::onCreateDefaultRepoSuccess(const QString& repo_id)
+{
+    startDownload(repo_id);
+}
+
+void InitVirtualDriveDialog::onCreateDefaultRepoFailure(const ApiError& error)
+{
+    if (error.type() == ApiError::HTTP_ERROR && error.httpErrorCode() == 404) {
+        fail(tr("Failed to create default library:\n\n"
+                "The server version must be 2.1 or higher to support this."));
+    } else {
+        fail(tr("Failed to create default library:\n%1").arg(error.toString()));
+    }
+}
+
+void InitVirtualDriveDialog::onDownloadRepoSuccess(const RepoDownloadInfo& info)
+{
+    int ret;
+    QString worktree = seafApplet->configurator()->worktreeDir();
+    QString error;
+
+    ret = seafApplet->rpcClient()->downloadRepo(info.repo_id,
+                                                info.repo_version, info.relay_id,
+                                                info.repo_name, worktree,
+                                                info.token, QString(),
+                                                info.magic, info.relay_addr,
+                                                info.relay_port, info.email,
+                                                info.random_key, info.enc_version,
+                                                info.more_info,
+                                                &error);
+
+    if (ret < 0) {
+        fail(tr("Failed to download default library:\n %1").arg(error));
+    } else {
+        check_download_timer_ = new QTimer(this);
+        connect(check_download_timer_, SIGNAL(timeout()), this, SLOT(checkDownloadProgress()));
+        check_download_timer_->start(kCheckDownloadInterval);
+
+        setStatusText(tr("Downloading default library..."));
+
+        mRunInBackgroundBtn->setVisible(true);
+        connect(mRunInBackgroundBtn, SIGNAL(clicked()), this, SLOT(hide()));
+    }
+}
+
+void InitVirtualDriveDialog::onDownloadRepoFailure(const ApiError& error)
+{
+    fail(tr("Failed to download default library:\n%1").arg(error.toString()));
+}
+
+void InitVirtualDriveDialog::openVirtualDisk()
+{
+    QDesktopServices::openUrl(QUrl::fromLocalFile(default_repo_path_));
+    accept();
+}
+
+void InitVirtualDriveDialog::finish()
+{
+    QString msg = tr("The default library has been downloaded.\n"
+                     "You can click the \"Open\" button to view it.");
+    setStatusText(msg);
+    setStatusIcon(":/images/sync/done@2x.png");
+
+    mFinishBtn->setVisible(true);
+    mOpenBtn->setVisible(true);
+
+    connect(mFinishBtn, SIGNAL(clicked()), this, SLOT(accept()));
+    connect(mOpenBtn, SIGNAL(clicked()), this, SLOT(openVirtualDisk()));
+}
+
+void InitVirtualDriveDialog::fail(const QString& reason)
+{
+    ensureVisible();
+
+    setStatusText(reason);
+    mFinishBtn->setVisible(true);
+    connect(mFinishBtn, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+void InitVirtualDriveDialog::checkDownloadProgress()
+{
+    // First check for error
+    std::vector<CloneTask> tasks;
+    if (seafApplet->rpcClient()->getCloneTasks(&tasks) < 0) {
+        return;
+    }
+
+    CloneTask task;
+    for (size_t i = 0; i < tasks.size(); i++) {
+        if (tasks[i].repo_id == default_repo_id_) {
+            task = tasks[i];
+            break;
+        }
+    }
+
+    if (!task.isValid()) {
+        return;
+    }
+
+    if (task.state != "done" && task.state != "error") {
+        return;
+    }
+
+    check_download_timer_->stop();
+
+    mRunInBackgroundBtn->setVisible(false);
+    ensureVisible();
+
+    if (task.state == "error") {
+        fail(tr("Error when downloading the default library: %1").arg(task.error_str));
+        return;
+    }
+
+    // Download is finished.
+    LocalRepo repo;
+    seafApplet->rpcClient()->getLocalRepo(default_repo_id_, &repo);
+    default_repo_path_ = repo.worktree;
+    finish();
+}
+
+
+void InitVirtualDriveDialog::setStatusText(const QString& status)
+{
+    mStatusText->setText(status);
+}
+
+void InitVirtualDriveDialog::setStatusIcon(const QString& path)
+{
+    mStatusIcon->setPixmap(QPixmap(path));
+}
+
+void InitVirtualDriveDialog::ensureVisible()
+{
+    show();
+    raise();
+    activateWindow();
+}
diff --git a/src/ui/init-vdrive-dialog.h b/src/ui/init-vdrive-dialog.h
new file mode 100644 (file)
index 0000000..ffd7c70
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef SEAFILE_CLIENT_INIT_VDRIVE_DIALOG_H
+#define SEAFILE_CLIENT_INIT_VDRIVE_DIALOG_H
+
+#include <QDialog>
+#include "ui_init-vdrive-dialog.h"
+#include "account.h"
+#include "api/requests.h"
+
+class LocalRepo;
+class QTimer;
+
+class InitVirtualDriveDialog : public QDialog,
+                               public Ui::InitVirtualDriveDialog
+{
+    Q_OBJECT
+public:
+    InitVirtualDriveDialog(const Account& account, QWidget *parent=0);
+
+private slots:
+    void onGetDefaultRepoSuccess(bool exists, const QString& repo_id);
+    void onGetDefaultRepoFailure(const ApiError& error);
+    void onCreateDefaultRepoSuccess(const QString& repo_id);
+    void onCreateDefaultRepoFailure(const ApiError& error);
+    void onDownloadRepoSuccess(const RepoDownloadInfo& info);
+    void onDownloadRepoFailure(const ApiError& error);
+    void checkDownloadProgress();
+    void start();
+    void onCancel();
+    void openVirtualDisk();
+
+private:
+    Q_DISABLE_COPY(InitVirtualDriveDialog)
+
+    void getDefaultRepo();
+    void startDownload(const QString& repo_id);
+    void createLoadingView();
+    void createDefaultRepo();
+    void setStatusText(const QString& status);
+    void setStatusIcon(const QString& path);
+    void ensureVisible();
+    void finish();
+    void fail(const QString& reason);
+
+    GetDefaultRepoRequest *get_default_repo_req_;
+    CreateDefaultRepoRequest *create_default_repo_req_;
+    DownloadRepoRequest *download_default_repo_req_;
+
+    QString default_repo_id_;
+    QString default_repo_path_;
+
+    Account account_;
+
+    QTimer *check_download_timer_;
+};
+
+#endif // SEAFILE_CLIENT_INIT_VDRIVE_DIALOG_H
diff --git a/src/ui/loading-view.cpp b/src/ui/loading-view.cpp
new file mode 100644 (file)
index 0000000..aa636c5
--- /dev/null
@@ -0,0 +1,68 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "loading-view.h"
+
+LoadingView::LoadingView(QWidget *parent)
+    : QLabel(parent)
+{
+    gif_ = new QMovie(":/images/loading-spinner.gif");
+    gif_->setScaledSize(QSize(24, 24));
+    gif_->setParent(this);
+    setMovie(gif_);
+    setAlignment(Qt::AlignCenter);
+}
+
+void LoadingView::showEvent(QShowEvent *event)
+{
+    gif_->start();
+    QWidget::showEvent(event);
+}
+
+void LoadingView::hideEvent(QHideEvent *event)
+{
+    gif_->stop();
+    QWidget::hideEvent(event);
+}
+
+void LoadingView::setQssStyleForTab()
+{
+    static const char *kLoadingViewQss = "border: 0; margin: 0;"
+                                         "border-top: 1px solid #DCDCDE;"
+                                         "background-color: #F5F5F7;";
+
+    setStyleSheet(kLoadingViewQss);
+}
+
+LoadMoreButton::LoadMoreButton(QWidget *parent)
+    : QWidget(parent)
+{
+    load_more_btn_ = new QToolButton;
+    load_more_btn_->setObjectName("loadMoreBtn");
+    load_more_btn_->setText(tr("load more"));
+    btn_layout_ = new QHBoxLayout(this);
+    btn_layout_->addWidget(load_more_btn_, Qt::AlignCenter);
+
+    loading_label_ = new LoadingView;
+
+    // Must set fill backgound because this button is used as an "index widget".
+    // See the doc of QAbstractItemView::setIndexWidget for details.
+    setAutoFillBackground(true);
+
+    connect(load_more_btn_, SIGNAL(clicked()),
+            this, SLOT(onBtnClicked()));
+}
+
+void LoadMoreButton::onBtnClicked()
+{
+    load_more_btn_->hide();
+
+    btn_layout_->addWidget(loading_label_, Qt::AlignCenter);
+
+    emit clicked();
+}
diff --git a/src/ui/loading-view.h b/src/ui/loading-view.h
new file mode 100644 (file)
index 0000000..f5429e1
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef SEAFILE_CLIENT_LOADING_VIEW_H_
+#define SEAFILE_CLIENT_LOADING_VIEW_H_
+
+#include <QWidget>
+#include <QToolButton>
+#include <QLabel>
+
+class QMovie;
+class QShowEvent;
+class QHideEvent;
+class QHBoxLayout;
+
+class LoadingView : public QLabel {
+    Q_OBJECT
+public:
+    LoadingView(QWidget *parent=0);
+    void setQssStyleForTab();
+
+protected:
+    void showEvent(QShowEvent *event);
+    void hideEvent(QHideEvent *event);
+
+private:
+    Q_DISABLE_COPY(LoadingView)
+
+    QMovie *gif_;
+};
+
+class LoadMoreButton : public QWidget {
+    Q_OBJECT
+public:
+    explicit LoadMoreButton(QWidget *parent=0);
+
+signals:
+    void clicked();
+
+private slots:
+    void onBtnClicked();
+
+private:
+    QHBoxLayout *btn_layout_;
+    QToolButton *load_more_btn_;
+    LoadingView *loading_label_;
+};
+
+#endif // SEAFILE_CLIENT_LOADING_VIEW_H_
diff --git a/src/ui/login-dialog.cpp b/src/ui/login-dialog.cpp
new file mode 100644 (file)
index 0000000..f313f98
--- /dev/null
@@ -0,0 +1,446 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QtNetwork>
+#include <QStringList>
+#include <QSettings>
+
+#include "settings-mgr.h"
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "login-dialog.h"
+#include "utils/utils.h"
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+#include "shib/shib-login-dialog.h"
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+namespace {
+
+const char *kUsedServerAddresses = "UsedServerAddresses";
+const char *const kPreconfigureServerAddr = "PreconfigureServerAddr";
+const char *const kPreconfigureServerAddrOnly = "PreconfigureServerAddrOnly";
+const char *const kPreconfigureShibbolethLoginUrl = "PreconfigureShibbolethLoginUrl";
+
+// 1. Returned by the server "X-Seafile-OTP: required" when login (if the user has 2FA enabled)
+// 2. The client would send this header, e.g. "X-Seafile-OTP: 123456" when login again
+const char *const kSeafileOTPHeader = "X-SEAFILE-OTP";
+// This header tells sever to remember this device and do not ask this
+// device for 2fa token in the next 90 days. The server would return a
+// "S2FA" token which should be saved by the device.
+const char *const kRememberDeviceHeader = "X-SEAFILE-2FA-TRUST-DEVICE";
+// 1. The "S2FA" token returned by the server when "X-SEAFILE-2FA-TRUST-DEVICE: 1" is used to login
+// 2. The client should send this device when login again so the server won't ask it for the 2FA token.
+const char *const kTwofactorHeader = "X-SEAFILE-S2FA";
+
+const char *const kSchemeHTTPS = "https";
+
+QStringList getUsedServerAddresses()
+{
+    QSettings settings;
+    settings.beginGroup(kUsedServerAddresses);
+    QStringList retval = settings.value("main").toStringList();
+    settings.endGroup();
+    QString preconfigure_addr = seafApplet->readPreconfigureExpandedString(kPreconfigureServerAddr);
+    if (!preconfigure_addr.isEmpty() && !retval.contains(preconfigure_addr)) {
+        retval.push_back(preconfigure_addr);
+    }
+    return retval;
+}
+
+void saveUsedServerAddresses(const QString &new_address)
+{
+    QSettings settings;
+    settings.beginGroup(kUsedServerAddresses);
+    QStringList list = settings.value("main").toStringList();
+    // put the last used address to the front
+    list.removeAll(new_address);
+    list.insert(0, new_address);
+    settings.setValue("main", list);
+    settings.endGroup();
+}
+
+} // namespace
+
+LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent)
+{
+    setupUi(this);
+    setWindowTitle(tr("Add an account"));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    request_ = NULL;
+    account_info_req_ = NULL;
+    is_remember_device_ = false;
+
+    mStatusText->setText("");
+    mLogo->setPixmap(QPixmap(":/images/seafile-32.png"));
+    QString preconfigure_addr = seafApplet->readPreconfigureExpandedString(kPreconfigureServerAddr);
+    if (seafApplet->readPreconfigureEntry(kPreconfigureServerAddrOnly).toBool() && !preconfigure_addr.isEmpty()) {
+        mServerAddr->setMaxCount(1);
+        mServerAddr->insertItem(0, preconfigure_addr);
+        mServerAddr->setCurrentIndex(0);
+        mServerAddr->setEditable(false);
+    } else {
+        mServerAddr->addItems(getUsedServerAddresses());
+        mServerAddr->clearEditText();
+    }
+    mServerAddr->setAutoCompletion(false);
+
+    mAutomaticLogin->setCheckState(Qt::Checked);
+
+    QString computerName = seafApplet->settingsManager()->getComputerName();
+    mComputerName->setText(computerName);
+
+    connect(mSubmitBtn, SIGNAL(clicked()), this, SLOT(doLogin()));
+
+    const QRect screen = QApplication::desktop()->screenGeometry();
+    move(screen.center() - this->rect().center());
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+    setupShibLoginLink();
+#else
+    mShibLoginLink->hide();
+#endif
+}
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+void LoginDialog::setupShibLoginLink()
+{
+    QString txt = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("Single Sign On"));
+    mShibLoginLink->setText(txt);
+    connect(mShibLoginLink, SIGNAL(linkActivated(const QString&)),
+            this, SLOT(loginWithShib()));
+}
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+void LoginDialog::initFromAccount(const Account& account)
+{
+    setWindowTitle(tr("Re-login"));
+    mTitle->setText(tr("Re-login"));
+    mServerAddr->setMaxCount(1);
+    mServerAddr->insertItem(0, account.serverUrl.toString());
+    mServerAddr->setCurrentIndex(0);
+    mServerAddr->setEditable(false);
+
+    mAutomaticLogin->setCheckState(account.isAutomaticLogin ? Qt::Checked : Qt::Unchecked);
+    mUsername->setText(account.username);
+    mPassword->setFocus(Qt::OtherFocusReason);
+}
+
+void LoginDialog::doLogin()
+{
+    if (!validateInputs()) {
+        return;
+    }
+    saveUsedServerAddresses(url_.toString());
+
+    mStatusText->setText(tr("Logging in..."));
+
+    disableInputs();
+
+    if (request_) {
+        request_->deleteLater();
+    }
+
+    request_ = new LoginRequest(url_, username_, password_, computer_name_);
+
+    if (!two_factor_auth_token_.isEmpty()) {
+        request_->setHeader(kSeafileOTPHeader, two_factor_auth_token_);
+    }
+
+    if (is_remember_device_) {
+        request_->setHeader(kRememberDeviceHeader, "1");
+    }
+
+    Account account =  seafApplet->accountManager()->getAccountByHostAndUsername(url_.host(), username_);
+    if (account.hasS2FAToken()) {
+        request_->setHeader(kTwofactorHeader, account.s2fa_token);
+    }
+
+    connect(request_, SIGNAL(success(const QString&, const QString&)),
+            this, SLOT(loginSuccess(const QString&, const QString&)));
+
+    connect(request_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(loginFailed(const ApiError&)));
+
+    request_->send();
+}
+
+void LoginDialog::disableInputs()
+{
+    mServerAddr->setEnabled(false);
+    mUsername->setEnabled(false);
+    mPassword->setEnabled(false);
+    mSubmitBtn->setEnabled(false);
+    mComputerName->setEnabled(false);
+}
+
+void LoginDialog::enableInputs()
+{
+    mServerAddr->setEnabled(true);
+    mUsername->setEnabled(true);
+    mPassword->setEnabled(true);
+    mSubmitBtn->setEnabled(true);
+    mComputerName->setEnabled(true);
+}
+
+void LoginDialog::onNetworkError(const QNetworkReply::NetworkError& error, const QString& error_string)
+{
+    showWarning(tr("Network Error:\n %1").arg(error_string));
+    enableInputs();
+
+    mStatusText->setText("");
+}
+
+void LoginDialog::onSslErrors(QNetworkReply* reply, const QList<QSslError>& errors)
+{
+    const QSslCertificate &cert = reply->sslConfiguration().peerCertificate();
+    qDebug() << "\n= SslErrors =\n" << dumpSslErrors(errors);
+    qDebug() << "\n= Certificate =\n" << dumpCertificate(cert);
+
+    if (seafApplet->detailedYesOrNoBox(tr("<b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?"),
+                                   dumpSslErrors(errors) + dumpCertificate(cert),
+                                   this,
+                                   false))
+        reply->ignoreSslErrors();
+}
+
+bool LoginDialog::validateInputs()
+{
+    QString serverAddr = mServerAddr->currentText();
+    QString protocol;
+    QUrl url;
+
+    if (serverAddr.size() == 0) {
+        showWarning(tr("Please enter the server address"));
+        return false;
+    } else {
+        if (!serverAddr.startsWith("http://") && !serverAddr.startsWith("https://")) {
+            showWarning(tr("%1 is not a valid server address").arg(serverAddr));
+            return false;
+        }
+
+        url = QUrl(serverAddr, QUrl::StrictMode);
+        if (!url.isValid()) {
+            showWarning(tr("%1 is not a valid server address").arg(serverAddr));
+            return false;
+        }
+    }
+
+    QString email = mUsername->text();
+    if (email.size() == 0) {
+        showWarning(tr("Please enter the username"));
+        return false;
+    }
+
+    if (mPassword->text().size() == 0) {
+        showWarning(tr("Please enter the password"));
+        return false;
+    }
+
+    QString computer_name = mComputerName->text().trimmed();
+    if (computer_name.size() == 0) {
+        showWarning(tr("Please enter the computer name"));
+        return false;
+    }
+
+    url_ = url;
+    username_ = mUsername->text();
+    password_ = mPassword->text();
+    computer_name_ = mComputerName->text();
+
+    seafApplet->settingsManager()->setComputerName(computer_name_);
+
+    return true;
+}
+
+void LoginDialog::loginSuccess(const QString& token, const QString& s2fa_token)
+{
+    // Some server configures mandatory http -> https redirect. In
+    // such cases, we must update the server url to use https,
+    // otherwise libcurl (used by the daemon) would be have trouble
+    // dealing with it.
+    if (url_.scheme() != kSchemeHTTPS && request_->reply()->url().scheme() == kSchemeHTTPS) {
+        qWarning("Detected server %s redirects to https", toCStr(url_.toString()));
+        url_.setScheme(kSchemeHTTPS);
+    }
+    if (account_info_req_) {
+        account_info_req_->deleteLater();
+    }
+    account_info_req_ =
+        new FetchAccountInfoRequest(Account(url_, username_, token, 0, false, true, s2fa_token));
+    connect(account_info_req_, SIGNAL(success(const AccountInfo&)), this,
+            SLOT(onFetchAccountInfoSuccess(const AccountInfo&)));
+    connect(account_info_req_, SIGNAL(failed(const ApiError&)), this,
+            SLOT(onFetchAccountInfoFailed(const ApiError&)));
+    account_info_req_->send();
+}
+
+void LoginDialog::onFetchAccountInfoFailed(const ApiError& error)
+{
+    loginFailed(error);
+}
+
+void LoginDialog::loginFailed(const ApiError& error)
+{
+    switch (error.type()) {
+    case ApiError::SSL_ERROR:
+        onSslErrors(error.sslReply(), error.sslErrors());
+        break;
+    case ApiError::NETWORK_ERROR:
+        onNetworkError(error.networkError(), error.networkErrorString());
+        break;
+    case ApiError::HTTP_ERROR:
+        onHttpError(error.httpErrorCode());
+    default:
+        // impossible
+        break;
+    }
+}
+
+void LoginDialog::onFetchAccountInfoSuccess(const AccountInfo& info)
+{
+    Account account = account_info_req_->account();
+    // The user may use the username to login, but we need to store the email
+    // to account database
+    account.username = info.email;
+    account.isAutomaticLogin =
+        mAutomaticLogin->checkState() == Qt::Checked;
+    if (seafApplet->accountManager()->saveAccount(account) < 0) {
+        showWarning(tr("Failed to save current account"));
+    }
+    else {
+        seafApplet->accountManager()->updateAccountInfo(account, info);
+        done(QDialog::Accepted);
+    }
+}
+
+void LoginDialog::onHttpError(int code)
+{
+    const QNetworkReply* reply = request_->reply();
+    if (reply->hasRawHeader(kSeafileOTPHeader) &&
+        QString(reply->rawHeader(kSeafileOTPHeader)) == "required") {
+        TwoFactorDialog two_factor_dialog;
+        if (two_factor_dialog.exec() == QDialog::Accepted) {
+            two_factor_auth_token_ = two_factor_dialog.getText();
+            is_remember_device_ = two_factor_dialog.rememberDeviceChecked();
+        }
+
+        if (!two_factor_auth_token_.isEmpty()) {
+            doLogin();
+            return;
+        }
+    } else {
+        QString err_msg, reason;
+        if (code == 400) {
+            reason = tr("Incorrect email or password");
+        } else if (code == 429) {
+            reason = tr("Logging in too frequently, please wait a minute");
+        } else if (code == 500) {
+            reason = tr("Internal Server Error");
+        }
+
+        if (reason.length() > 0) {
+            err_msg = tr("Failed to login: %1").arg(reason);
+        } else {
+            err_msg = tr("Failed to login");
+        }
+
+        showWarning(err_msg);
+    }
+
+    enableInputs();
+
+    mStatusText->setText("");
+}
+
+void LoginDialog::showWarning(const QString& msg)
+{
+    seafApplet->warningBox(msg, this);
+}
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+
+bool LoginDialog::getShibLoginUrl(const QString& last_shib_url, QUrl *url_out)
+{
+    QString server_addr = last_shib_url;
+    QUrl url;
+
+    while (true) {
+        bool ok;
+        server_addr =
+            seafApplet->getText(this,
+                                tr("Single Sign On"),
+                                tr("%1 Server Address").arg(getBrand()),
+                                QLineEdit::Normal,
+                                server_addr,
+                                &ok);
+        server_addr = server_addr.trimmed();
+
+        // exit when user hits cancel button
+        if (!ok) {
+            return false;
+        }
+
+        if (server_addr.isEmpty()) {
+            showWarning(tr("Server address must not be empty").arg(server_addr));
+            continue;
+        }
+
+        if (!server_addr.startsWith("https://")) {
+            showWarning(tr("%1 is not a valid server address. It has to start with 'https://'").arg(server_addr));
+            continue;
+        }
+
+        url = QUrl(server_addr, QUrl::StrictMode);
+        if (!url.isValid()) {
+            showWarning(tr("%1 is not a valid server address").arg(server_addr));
+            continue;
+        }
+
+        *url_out = url;
+        return true;
+    }
+}
+
+void LoginDialog::loginWithShib()
+{
+    QString server_addr =
+        seafApplet->readPreconfigureEntry(kPreconfigureShibbolethLoginUrl)
+            .toString()
+            .trimmed();
+    if (!server_addr.isEmpty()) {
+        if (QUrl(server_addr).isValid()) {
+            qWarning("Using preconfigured shibboleth login url: %s\n",
+                     toCStr(server_addr));
+        } else {
+            qWarning("Invalid preconfigured shibboleth login url: %s\n",
+                     toCStr(server_addr));
+            server_addr = "";
+        }
+    }
+
+    QUrl url = server_addr;
+    if (server_addr.isEmpty()) {
+        // When we reach here, there is no preconfigured shibboleth login url,
+        // or the preconfigured url is invalid. So we ask the user for the url.
+        server_addr = seafApplet->settingsManager()->getLastShibUrl();
+        if (!getShibLoginUrl(server_addr, &url)) {
+            return;
+        }
+    }
+
+    seafApplet->settingsManager()->setLastShibUrl(url.toString());
+
+    ShibLoginDialog shib_dialog(url, mComputerName->text(), this);
+    if (shib_dialog.exec() == QDialog::Accepted) {
+        accept();
+    }
+}
+#endif // HAVE_SHIBBOLETH_SUPPORT
diff --git a/src/ui/login-dialog.h b/src/ui/login-dialog.h
new file mode 100644 (file)
index 0000000..e04659d
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef SEAFILE_CLIENT_LOGIN_DIALOG_H
+#define SEAFILE_CLIENT_LOGIN_DIALOG_H
+
+#include <QDialog>
+#include "ui_login-dialog.h"
+
+#include <QUrl>
+#include <QString>
+#include <QNetworkReply>
+
+#include "two-factor-dialog.h"
+
+class Account;
+class LoginRequest;
+class QNetworkReply;
+class QSslError;
+class ApiError;
+class FetchAccountInfoRequest;
+class AccountInfo;
+
+class LoginDialog : public QDialog,
+                    public Ui::LoginDialog
+{
+    Q_OBJECT
+public:
+    LoginDialog(QWidget *parent=0);
+    void initFromAccount(const Account& account);
+
+private slots:
+    void doLogin();
+    void loginSuccess(const QString& token, const QString& s2fa_token);
+    void loginFailed(const ApiError& error);
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+    void loginWithShib();
+#endif // HAVE_SHIBBOLETH_SUPPORT
+    void onFetchAccountInfoSuccess(const AccountInfo& info);
+    void onFetchAccountInfoFailed(const ApiError&);
+
+private:
+    Q_DISABLE_COPY(LoginDialog);
+
+    enum LoginMode {
+        LOGIN_NORMAL = 0,
+        LOGIN_SHIB
+    };
+
+    void setupShibLoginLink();
+    bool validateInputs();
+    void disableInputs();
+    void enableInputs();
+    void showWarning(const QString& msg);
+
+    void onNetworkError(const QNetworkReply::NetworkError& error, const QString& error_string);
+    void onSslErrors(QNetworkReply *reply, const QList<QSslError>& errors);
+    void onHttpError(int code);
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+    bool getShibLoginUrl(const QString& last_shib_url, QUrl *url_out);
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+    QUrl url_;
+    QString username_;
+    QString password_;
+    QString computer_name_;
+    bool is_remember_device_;
+    LoginRequest *request_;
+    FetchAccountInfoRequest *account_info_req_;
+
+    QString two_factor_auth_token_;
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+    LoginMode mode_;
+#endif // HAVE_SHIBBOLETH_SUPPORT
+};
+
+#endif // SEAFILE_CLIENT_LOGIN_DIALOG_H
diff --git a/src/ui/logout-view.cpp b/src/ui/logout-view.cpp
new file mode 100644 (file)
index 0000000..7400ab1
--- /dev/null
@@ -0,0 +1,64 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include "seafile-applet.h"
+#include "account-mgr.h"
+
+#include "logout-view.h"
+
+LogoutView::LogoutView(QWidget *parent)
+    : QWidget(parent)
+{
+    setObjectName("LogoutView");
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    setLayout(layout);
+
+    label_ = new QLabel;
+    label_->setAlignment(Qt::AlignCenter);
+
+    layout->addWidget(label_);
+    layout->setContentsMargins(0, 0, 0, 0);
+
+    connect(seafApplet->accountManager(), SIGNAL(accountsChanged()),
+            this, SLOT(onAccountChanged()));
+
+    onAccountChanged();
+}
+
+void LogoutView::setQssStyleForTab()
+{
+    static const char *kLogoutViewQss = "border: 0; margin: 0;"
+                              "border-top: 1px solid #DCDCDE;"
+                              "background-color: #F5F5F7;";
+
+    setStyleSheet(kLogoutViewQss);
+}
+
+void LogoutView::onAccountChanged()
+{
+    // disconnect current signal
+    disconnect(label_, SIGNAL(linkActivated(const QString&)), 0, 0);
+
+    QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>");
+
+    if (seafApplet->accountManager()->hasAccount()) {
+        connect(label_, SIGNAL(linkActivated(const QString&)),
+                this, SLOT(reloginCurrentAccount()));
+        label_->setText(tr("You are logout. Please ") + link.arg(tr("login")));
+    } else {
+        connect(label_, SIGNAL(linkActivated(const QString&)),
+                seafApplet->accountManager(), SIGNAL(requireAddAccount()));
+        label_->setText(link.arg(tr("Add an account")));
+    }
+}
+
+void LogoutView::reloginCurrentAccount()
+{
+    Account account = seafApplet->accountManager()->accounts().front();
+    seafApplet->accountManager()->reloginAccount(account);
+}
diff --git a/src/ui/logout-view.h b/src/ui/logout-view.h
new file mode 100644 (file)
index 0000000..0a2aa34
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SEAFILE_CLIENT_LOGOUT_VIEW_H_
+#define SEAFILE_CLIENT_LOGOUT_VIEW_H_
+
+#include <QWidget>
+
+class QShowEvent;
+class QLabel;
+class Account;
+
+class LogoutView : public QWidget {
+    Q_OBJECT
+public:
+    LogoutView(QWidget *parent=0);
+    void setQssStyleForTab();
+
+private slots:
+    void onAccountChanged();
+    void reloginCurrentAccount();
+
+private:
+    Q_DISABLE_COPY(LogoutView)
+    QLabel *label_;
+};
+
+#endif // SEAFILE_CLIENT_LOGOUT_VIEW_H_
diff --git a/src/ui/main-window.cpp b/src/ui/main-window.cpp
new file mode 100644 (file)
index 0000000..c214f70
--- /dev/null
@@ -0,0 +1,286 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QApplication>
+#include <QDesktopServices>
+#include <QFile>
+#include <QTextStream>
+#include <QDir>
+#include <QCoreApplication>
+
+#include <QDialog>
+#include <QTabBar>
+#include <QVBoxLayout>
+
+#include "cloud-view.h"
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "tray-icon.h"
+#include "login-dialog.h"
+#include "utils/utils.h"
+#include "utils/utils-mac.h"
+#include "utils/utils-win.h"
+#include "filebrowser/auto-update-mgr.h"
+
+#include "main-window.h"
+
+namespace {
+
+enum WIDGET_INDEX {
+    INDEX_CLOUD_VIEW = 0,
+    INDEX_LOCAL_VIEW
+};
+
+const int kMinimumTopMargin = 20;
+const int kPreferredTopMargin = 150;
+
+const int kMinimumRightMargin = 100;
+const int kPreferredRightMargin = 150;
+
+QSize getReasonableWindowSize(const QSize &in)
+{
+    QSize size;
+    const QRect screen = QApplication::desktop()->availableGeometry();
+    return QSize(qMin(in.width(), screen.width() - kMinimumRightMargin),
+                 qMin(in.height(), screen.height() - kMinimumTopMargin));
+}
+
+// Detect if the pos is outside the screens.
+bool isOutsideScreens(const QRect &rect) {
+    QList<QScreen*> screens = QGuiApplication::screens();
+    for (int i = 0; i < screens.size(); ++i) {
+        if (screens[i]->availableGeometry().contains(rect))
+            return false;
+    }
+    return true;
+}
+
+} // namespace
+
+MainWindow::MainWindow()
+{
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowTitle(getBrand());
+
+    // Qt::Tool hides the taskbar entry on windows
+    // setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
+
+    Qt::WindowFlags flags = Qt::Window | Qt::WindowSystemMenuHint;
+    if (shouldUseFramelessWindow()) {
+        flags |= Qt::FramelessWindowHint;
+    } else {
+        flags |= Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint |
+            Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint;
+    }
+
+    setWindowFlags(flags);
+
+    cloud_view_ = new CloudView;
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->setContentsMargins(0, 0, 0, 0);
+    layout->addWidget(cloud_view_);
+
+    QWidget *wrapper = new QWidget;
+    wrapper->setObjectName("mainWrapper");
+    wrapper->setLayout(layout);
+    if (shouldUseFramelessWindow()) {
+        setAttribute(Qt::WA_TranslucentBackground, true);
+    } else {
+        wrapper->setStyleSheet("QWidget#mainWrapper {border : 0; border-radius: 0px;}");
+    }
+
+    setCentralWidget(wrapper);
+
+    createActions();
+
+#if defined(Q_OS_MAC) && (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
+    connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
+            this, SLOT(checkShowWindow()));
+#endif
+}
+
+void MainWindow::hide()
+{
+    writeSettings();
+    QMainWindow::hide();
+}
+
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+    event->accept();
+    hide();
+}
+
+bool MainWindow::event(QEvent *ev)
+{
+    bool ret = QMainWindow::event(ev);
+
+    if (isMinimized() && ev->type() == QEvent::WindowStateChange) {
+        QWindowStateChangeEvent *wev = (QWindowStateChangeEvent *)ev;
+        if (wev->oldState() != Qt::WindowMinimized) {
+            writeSettings();
+        }
+    }
+
+    if (ev->type() == QEvent::Hide) {
+        writeSettings();
+    }
+
+    return ret;
+}
+
+void MainWindow::changeEvent(QEvent *event)
+{
+    if (!shouldUseFramelessWindow()) {
+        QWidget::changeEvent(event);
+    }
+// #if defined(Q_OS_WIN32)
+//     /*
+//      * Solve the problem of restoring a minimized frameless window on Windows
+//      * See http://stackoverflow.com/questions/18614661/how-to-not-hide-taskbar-item-during-using-hide
+//      */
+//     if(event->type() == QEvent::WindowStateChange) {
+//         if(windowState() & Qt::WindowMinimized ) {
+//             //do something after minimize
+//         } else {
+//             cloud_view_->hide();
+//             cloud_view_->show();
+//         }
+//     }
+// #endif
+}
+
+void MainWindow::showEvent(QShowEvent *event)
+{
+    readSettings();
+#if defined(Q_OS_WIN32)
+    /*
+     * Another hack to Solve the problem of restoring a minimized frameless window on Windows
+     * See http://qt-project.org/forums/viewthread/7081
+     */
+    if (shouldUseFramelessWindow()) {
+        QApplication::postEvent(this, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
+    }
+#endif
+    QWidget::showEvent(event);
+
+}
+
+// handle osx's applicationShouldHandleReopen
+// QTBUG-10899 OS X: Add support for ApplicationState capability
+void MainWindow::checkShowWindow()
+{
+    // printf ("app inactive = %s\n", (qApp->applicationState() & Qt::ApplicationInactive) ? "yes" : "no");
+#if defined(Q_OS_MAC) && (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
+    if (qApp->applicationState() & Qt::ApplicationActive) {
+        if (qApp->activeModalWidget() || qApp->activePopupWidget() || qApp->activeWindow())
+            return;
+        showWindow();
+    }
+#endif
+}
+
+void MainWindow::createActions()
+{
+    refresh_qss_action_ = new QAction(QIcon(":/images/toolbar/refresh-gray.png"), tr("Refresh"), this);
+    connect(refresh_qss_action_, SIGNAL(triggered()), this, SLOT(refreshQss()));
+}
+
+void MainWindow::keyPressEvent(QKeyEvent *event)
+{
+    if (event->key() == Qt::Key_F5) {
+        refreshQss();
+        return;
+    } else if (event->key() == Qt::Key_F6) {
+        AutoUpdateManager::instance()->dumpCacheStatus();
+        return;
+    }
+
+    // if (event->key() == Qt::Key_F6) {
+    //     showTestDialog(this);
+    //     return;
+    // }
+
+    QMainWindow::keyPressEvent(event);
+}
+
+void MainWindow::showWindow()
+{
+    showNormal();
+    show();
+    raise();
+    activateWindow();
+    // a hack with UIElement application
+#ifdef Q_OS_MAC
+    utils::mac::orderFrontRegardless(seafApplet->mainWindow()->winId());
+#endif
+}
+
+void MainWindow::refreshQss()
+{
+    seafApplet->refreshQss();
+}
+
+void MainWindow::writeSettings()
+{
+    QSettings settings;
+
+    settings.beginGroup("MainWindow");
+    settings.setValue("size", size());
+    settings.setValue("pos", pos());
+    settings.endGroup();
+}
+
+QPoint MainWindow::getDefaultPosition(const QSize& size)
+{
+    const QRect screen = QApplication::desktop()->availableGeometry();
+    const QPoint top_right = screen.topRight();
+
+    int extra_height = qMax(screen.height() - size.height(), kMinimumTopMargin) / 2;
+    int right_margin = rect().width() + qMin(kPreferredRightMargin, (int)(0.1 * screen.width()));
+    int top_margin = qMin(qMin(extra_height, kPreferredTopMargin), (int)(0.1 * screen.width()));
+
+    return QPoint(top_right.x() - right_margin, top_right.y() + top_margin);
+}
+
+void MainWindow::readSettings()
+{
+    QPoint pos;
+    // Default size of the main window from qt.css.
+    const QSize default_size(325, 585);
+    QSize size;
+    QSettings settings;
+    settings.beginGroup("MainWindow");
+
+    static bool first_show = true;
+
+    if (first_show && seafApplet->configurator()->firstUse()) {
+        size = default_size;
+        pos = getDefaultPosition(default_size);
+    } else {
+        size = settings.value("size").toSize();
+        if (!size.isValid()) {
+            size = default_size;
+        } else {
+            size = getReasonableWindowSize(size);
+        }
+
+        pos = settings.value("pos", getDefaultPosition(size)).toPoint();
+
+        // we don't want to be out of screen at least 1/10 size
+        if (isOutsideScreens(QRect(pos, size / 10))) {
+            pos = getDefaultPosition(size);
+        }
+    }
+
+    first_show = false;
+
+    move(pos);
+    resize(size);
+}
diff --git a/src/ui/main-window.h b/src/ui/main-window.h
new file mode 100644 (file)
index 0000000..8fb59cb
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef SEAFILE_MAINWINDOW_H
+#define SEAFILE_MAINWINDOW_H
+
+#include <QMainWindow>
+
+class QAction;
+class QToolBar;
+class QResizeEvent;
+class QSize;
+
+class CloudView;
+
+class MainWindow : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    MainWindow();
+
+    void keyPressEvent(QKeyEvent *event);
+    void showWindow();
+    void hide();
+
+    void readSettings();
+    void writeSettings();
+
+protected:
+    void createActions();
+    bool event(QEvent *event);
+    void changeEvent(QEvent *event);
+
+private slots:
+    void refreshQss();
+    void closeEvent(QCloseEvent *event);
+    void showEvent(QShowEvent *event);
+    void checkShowWindow(); //dummy slot if qt version is lower than 5.2.0
+
+private:
+    Q_DISABLE_COPY(MainWindow)
+
+    QPoint getDefaultPosition(const QSize& size);
+
+    QAction *refresh_qss_action_;
+
+    // ToolBar
+    QToolBar *tool_bar_;
+
+    QTabWidget *main_widget_;
+
+    CloudView *cloud_view_;
+};
+
+#endif  // SEAFILE_MAINWINDOW_H
diff --git a/src/ui/private-share-dialog.cpp b/src/ui/private-share-dialog.cpp
new file mode 100644 (file)
index 0000000..511d476
--- /dev/null
@@ -0,0 +1,1055 @@
+#include <QComboBox>
+#include <QCompleter>
+#include <QLineEdit>
+#include <QPainter>
+#include <QResizeEvent>
+#include <QStringList>
+#include <QStringListModel>
+#include <QDateTime>
+#include <QScrollBar>
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "private-share-dialog.h"
+#include "seafile-applet.h"
+#include "utils/file-utils.h"
+#include "utils/utils.h"
+
+namespace
+{
+enum {
+    COLUMN_NAME = 0,
+    COLUMN_PERMISSION,
+    MAX_COLUMN,
+};
+
+enum {
+    INDEX_USER_NAME = 0,
+    INDEX_GROUP_NAME,
+};
+
+const int kPermissionColumnWidth = 150;
+const int kNameColumnWidth = 300;
+const int kDefaultColumnHeight = 40;
+const int kIndicatorIconWidth = 10;
+const int kIndicatorIconHeight = 8;
+
+const int kMarginLeft = 2;
+const int kMarginTop = 2;
+const int kPadding = 2;
+const int kMarginBetweenPermissionAndIndicator = 10;
+
+const QColor kSelectedItemBackgroundcColor("#F9E0C7");
+const QColor kItemBackgroundColor("white");
+const QColor kItemBottomBorderColor("#f3f3f3");
+const QColor kItemColor("black");
+
+} // namespace
+
+PrivateShareDialog::PrivateShareDialog(const Account& account,
+                                       const QString& repo_id,
+                                       const QString& repo_name,
+                                       const QString& path,
+                                       bool to_group,
+                                       QWidget* parent)
+    : QDialog(parent),
+      account_(account),
+      repo_id_(repo_id),
+      repo_name_(repo_name),
+      path_(path),
+      to_group_(to_group),
+      request_in_progress_(false)
+{
+    setupUi(this);
+
+    setWindowTitle(
+        tr("Share %1")
+            .arg(path.length() <= 1 ? repo_name : ::getBaseName(path)));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+#if defined(Q_OS_MAC)
+    layout()->setContentsMargins(6, 6, 6, 6);
+    layout()->setSpacing(5);
+#endif
+
+    username_input_ = new QLineEdit(this);
+    username_input_->setObjectName("mUsernameInputBar");
+    groupname_input_ = new QComboBox(this);
+
+    mInputStack->insertWidget(INDEX_USER_NAME, username_input_);
+    mInputStack->insertWidget(INDEX_GROUP_NAME, groupname_input_);
+
+    if (to_group) {
+        mInputStack->setCurrentIndex(INDEX_GROUP_NAME);
+        groupname_input_->setEditable(true);
+        groupname_input_->clearEditText();
+        // The place holder text for the line editor of the combo box must be
+        // set
+        // after setEditable(true), because lineEdit() returns NULL before that.
+        groupname_input_->lineEdit()->setPlaceholderText(
+            tr("Enter the group name"));
+        groupname_input_->completer()->setCompletionMode(
+            QCompleter::PopupCompletion);
+        groupname_input_->clearEditText();
+    }
+    else {
+        mInputStack->setCurrentIndex(INDEX_USER_NAME);
+        username_input_->setPlaceholderText(tr("Enter user name or email address"));
+    }
+    mOkBtn->setEnabled(false);
+    mPermission->setCurrentIndex(0);
+    createTable();
+
+    if (to_group_) {
+        fetchGroupsForCompletion();
+    } else {
+        user_name_completer_.reset(new SeafileUserNameCompleter(account_, username_input_));
+        connect(lineEdit(), SIGNAL(returnPressed()), this, SLOT(onUserNameChoosed()));
+        getExistingShardItems();
+    }
+
+    connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkBtnClicked()));
+    connect(mCancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
+
+    connect(table_, SIGNAL(clicked(const QModelIndex&)), mStatusText,
+            SLOT(clear()));
+    connect(lineEdit(), SIGNAL(textChanged(const QString&)), mStatusText,
+            SLOT(clear()));
+    connect(lineEdit(), SIGNAL(textChanged(const QString&)), this,
+            SLOT(onNameInputEdited()));
+    connect(model_, SIGNAL(modelReset()), this, SLOT(selectFirstRow()));
+
+    adjustSize();
+    disableInputs();
+}
+
+void PrivateShareDialog::selectFirstRow()
+{
+    // for (int i = 0; i < model_->rowCount(); i++) {
+    //     table_->openPersistentEditor(model_->index(i, COLUMN_PERMISSION));
+    // }
+
+    // Select the first row of the table, so that the indicator would be
+    // painted, to tell the user the permission is editable.
+    if (!table_->currentIndex().isValid()) {
+        table_->setCurrentIndex(model_->index(0, 0));
+    }
+}
+
+void PrivateShareDialog::createTable()
+{
+    table_ = new SharedItemsTableView(this);
+    // table_->setEditTriggers(QAbstractItemView::AllEditTriggers);
+    model_ = new SharedItemsTableModel(
+        to_group_ ? SHARE_TO_GROUP : SHARE_TO_USER, this);
+    table_->setModel(model_);
+    QVBoxLayout* vlayout = (QVBoxLayout*)mFrame->layout();
+    vlayout->insertWidget(1, table_);
+
+    table_->setItemDelegate(new SharedItemDelegate(this));
+    table_->setEditTriggers(QAbstractItemView::SelectedClicked);
+
+    // Overloaded signal for updating group share.
+    connect(model_, SIGNAL(updateShareItem(int, SharePermission)), this,
+            SLOT(onUpdateShareItem(int, SharePermission)));
+    // Overloaded signal for updating user share.
+    connect(model_, SIGNAL(updateShareItem(const SeafileUser&, SharePermission)),
+            this, SLOT(onUpdateShareItem(const SeafileUser&, SharePermission)));
+
+    // Overloaded signal for removing group share.
+    connect(model_, SIGNAL(removeShareItem(int, SharePermission)), this,
+            SLOT(onRemoveShareItem(int, SharePermission)));
+    // Overloaded signal for removing user share.
+    connect(model_, SIGNAL(removeShareItem(const SeafileUser&, SharePermission)),
+            this, SLOT(onRemoveShareItem(const SeafileUser&, SharePermission)));
+}
+
+void PrivateShareDialog::onNameInputEdited()
+{
+    if (to_group_) {
+        mOkBtn->setEnabled(!lineEdit()->text().trimmed().isEmpty());
+    } else {
+        // We only enable the confirm button after the user chooses an candidate
+        // from the completion list.
+        mOkBtn->setEnabled(false);
+    }
+}
+
+void PrivateShareDialog::fetchGroupsForCompletion()
+{
+    fetch_groups_request_.reset(new FetchGroupsRequest(account_));
+    fetch_groups_request_->send();
+    connect(fetch_groups_request_.data(),
+            SIGNAL(success(const QList<SeafileGroup>&)),
+            this, SLOT(onFetchGroupsSuccess(const QList<SeafileGroup>&)));
+    connect(fetch_groups_request_.data(), SIGNAL(failed(const ApiError&)), this,
+            SLOT(onFetchContactsFailed(const ApiError&)));
+}
+
+void PrivateShareDialog::onUpdateShareItem(int group_id,
+                                           SharePermission permission)
+{
+    request_.reset(new PrivateShareRequest(account_, repo_id_, path_, SeafileUser(),
+                                           group_id, permission, SHARE_TO_GROUP,
+                                           PrivateShareRequest::UPDATE_SHARE));
+
+    connect(request_.data(), SIGNAL(success()), this,
+            SLOT(onUpdateShareSuccess()));
+    connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
+            SLOT(onUpdateShareFailed(const ApiError&)));
+
+    // disableInputs();
+    request_in_progress_ = true;
+    request_->send();
+}
+
+void PrivateShareDialog::onUpdateShareItem(const SeafileUser& user,
+                                           SharePermission permission)
+{
+    request_.reset(new PrivateShareRequest(account_, repo_id_, path_, user, 0,
+                                           permission, SHARE_TO_USER,
+                                           PrivateShareRequest::UPDATE_SHARE));
+
+    connect(request_.data(), SIGNAL(success()), this,
+            SLOT(onUpdateShareSuccess()));
+    connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
+            SLOT(onUpdateShareFailed(const ApiError&)));
+
+    // disableInputs();
+    request_in_progress_ = true;
+    request_->send();
+}
+
+void PrivateShareDialog::onUpdateShareSuccess()
+{
+    request_in_progress_ = false;
+    // seafApplet->messageBox(tr("Shared successfully"), this);
+    if (to_group_) {
+        GroupShareInfo info;
+        info.group = groups_by_id_[request_->groupId()];
+        info.permission = request_.data()->permission();
+        model_->addNewShareInfo(info);
+        table_->setCurrentIndex(model_->getIndexByGroup(info.group.id));
+    }
+    else {
+        UserShareInfo info;
+        info.user = request_.data()->user();
+        info.permission = request_.data()->permission();
+        model_->addNewShareInfo(info);
+        table_->setCurrentIndex(model_->getIndexByUser(info.user));
+    }
+    model_->shareOperationSuccess();
+    mStatusText->setText(tr("Updated successfully"));
+}
+
+void PrivateShareDialog::onUpdateShareFailed(const ApiError& error)
+{
+    request_in_progress_ = false;
+    showWarning(tr("Share Operation Failed: %1").arg(error.toString()));
+    model_->shareOperationFailed(request_->shareOperation());
+}
+
+void PrivateShareDialog::onRemoveShareItem(int group_id,
+                                           SharePermission permission)
+{
+    request_.reset(new PrivateShareRequest(account_, repo_id_, path_, SeafileUser(),
+                                           group_id, permission, SHARE_TO_GROUP,
+                                           PrivateShareRequest::REMOVE_SHARE));
+
+    connect(request_.data(), SIGNAL(success()), this,
+            SLOT(onRemoveShareSuccess()));
+    connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
+            SLOT(onRemoveShareFailed(const ApiError&)));
+
+    // disableInputs();
+    request_in_progress_ = true;
+    request_->send();
+}
+
+void PrivateShareDialog::onRemoveShareSuccess()
+{
+    request_in_progress_ = false;
+    model_->shareOperationSuccess();
+    mStatusText->setText(tr("Removed successfully"));
+}
+
+void PrivateShareDialog::onRemoveShareFailed(const ApiError& error)
+{
+    request_in_progress_ = false;
+    showWarning(tr("Share Operation Failed: %1").arg(error.toString()));
+    model_->shareOperationFailed(request_->shareOperation());
+}
+
+void PrivateShareDialog::onRemoveShareItem(const SeafileUser& user,
+                                           SharePermission permission)
+{
+    request_.reset(new PrivateShareRequest(account_, repo_id_, path_, user, 0,
+                                           permission, SHARE_TO_USER,
+                                           PrivateShareRequest::REMOVE_SHARE));
+
+    connect(request_.data(), SIGNAL(success()), this,
+            SLOT(onRemoveShareSuccess()));
+    connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
+            SLOT(onRemoveShareFailed(const ApiError&)));
+
+    // disableInputs();
+    request_in_progress_ = true;
+    request_->send();
+}
+
+
+void PrivateShareDialog::onFetchGroupsSuccess(const QList<SeafileGroup>& groups)
+{
+    QStringList candidates;
+    foreach (const SeafileGroup& group, groups) {
+        candidates << group.name;
+        groups_by_id_[group.id] = group;
+    }
+
+    if (!candidates.isEmpty()) {
+        groupname_input_->addItems(candidates);
+        groupname_input_->clearEditText();
+    }
+
+    getExistingShardItems();
+}
+
+void PrivateShareDialog::getExistingShardItems()
+{
+    get_shared_items_request_.reset(
+        new GetPrivateShareItemsRequest(account_, repo_id_, path_));
+
+    connect(get_shared_items_request_.data(),
+            SIGNAL(success(const QList<GroupShareInfo>&,
+                           const QList<UserShareInfo>&)),
+            this, SLOT(onGetSharedItemsSuccess(const QList<GroupShareInfo>&,
+                                               const QList<UserShareInfo>&)));
+    connect(get_shared_items_request_.data(), SIGNAL(failed(const ApiError&)),
+            this, SLOT(onGetSharedItemsFailed(const ApiError&)));
+
+    get_shared_items_request_->send();
+}
+
+void PrivateShareDialog::onGetSharedItemsSuccess(
+    const QList<GroupShareInfo>& group_shares,
+    const QList<UserShareInfo>& user_shares)
+{
+    model_->setShareInfo(group_shares, user_shares);
+    selectFirstRow();
+    enableInputs();
+}
+
+void PrivateShareDialog::onGetSharedItemsFailed(const ApiError& error)
+{
+    showWarning(tr("Failed to get share information of the folder"));
+    reject();
+}
+
+void PrivateShareDialog::onFetchContactsFailed(const ApiError& error)
+{
+    showWarning(tr("Failed to get your groups and contacts information"));
+    reject();
+}
+
+SharePermission PrivateShareDialog::currentPermission()
+{
+    return mPermission->currentIndex() == 0 ? READ_WRITE : READ_ONLY;
+}
+
+bool PrivateShareDialog::validateInputs()
+{
+    QString name = lineEdit()->text().trimmed();
+    if (name.isEmpty()) {
+        showWarning(to_group_ ? tr("Please enter the group name")
+                              : tr("Please enter the username"));
+        return false;
+    }
+
+    SharePermission permission = currentPermission();
+
+    if (to_group_) {
+        SeafileGroup group;
+        bool found = false;
+        foreach (const SeafileGroup& g, groups_by_id_.values()) {
+            if (g.name == name) {
+                group = g;
+                found = true;
+            }
+        }
+        if (!found) {
+            showWarning(tr("No such group \"%1\"").arg(name));
+            return false;
+        }
+        if (model_->shareExists(group.id)) {
+            GroupShareInfo info = model_->shareInfo(group.id);
+            if (info.permission == permission) {
+                showWarning(tr("Already shared to group %1").arg(name));
+            }
+            return false;
+        }
+    }
+    else {
+        const SeafileUser& user = user_name_completer_->currentSelectedUser();
+        if (!user.isValid()) {
+            showWarning(tr("Please enter the username"));
+            return false;
+        }
+
+        if (model_->shareExists(user)) {
+            UserShareInfo info = model_->shareInfo(user);
+            if (info.permission == permission) {
+                showWarning(tr("Already shared to user %1").arg(name));
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+SeafileGroup PrivateShareDialog::findGroup(const QString& name)
+{
+    foreach (const SeafileGroup& group, groups_by_id_.values()) {
+        if (group.name == name) {
+            return group;
+        }
+    }
+    return SeafileGroup();
+}
+
+void PrivateShareDialog::onUserNameChoosed()
+{
+    const SeafileUser& user = user_name_completer_->currentSelectedUser();
+    if (user.isValid()) {
+        mOkBtn->setEnabled(true);
+    }
+}
+
+void PrivateShareDialog::onOkBtnClicked()
+{
+    if (!validateInputs()) {
+        return;
+    }
+    if (request_in_progress_) {
+        showWarning(tr("The previous operation is still in progres"));
+        return;
+    }
+
+    // disableInputs();
+    SeafileGroup group;
+    SeafileUser user;
+    QString name = lineEdit()->text().trimmed();
+    if (to_group_) {
+        group = findGroup(name);
+    }
+    else {
+        user = user_name_completer_->currentSelectedUser();
+    }
+    request_.reset(new PrivateShareRequest(
+        account_, repo_id_, path_, user, group.id, currentPermission(),
+        to_group_ ? SHARE_TO_GROUP : SHARE_TO_USER,
+        PrivateShareRequest::ADD_SHARE));
+
+    connect(request_.data(), SIGNAL(success()), this, SLOT(onShareSuccess()));
+
+    connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
+            SLOT(onShareFailed(const ApiError&)));
+
+    request_in_progress_ = true;
+    request_->send();
+
+    if (to_group_) {
+        GroupShareInfo info;
+        info.group = group;
+        info.permission = currentPermission();
+        model_->addNewShareInfo(info);
+    }
+    else {
+        UserShareInfo info;
+        info.user = user;
+        info.permission = currentPermission();
+        model_->addNewShareInfo(info);
+    }
+}
+
+void PrivateShareDialog::disableInputs()
+{
+    toggleInputs(false);
+}
+
+void PrivateShareDialog::enableInputs()
+{
+    toggleInputs(true);
+}
+
+void PrivateShareDialog::toggleInputs(bool enabled)
+{
+    groupname_input_->setEnabled(enabled);
+    username_input_->setEnabled(enabled);
+    mOkBtn->setEnabled(enabled);
+    mCancelBtn->setEnabled(enabled);
+    mPermission->setEnabled(enabled);
+}
+
+void PrivateShareDialog::onShareSuccess()
+{
+    // seafApplet->messageBox(tr("Shared successfully"), this);
+    request_in_progress_ = false;
+    model_->shareOperationSuccess();
+    mStatusText->clear();
+}
+
+void PrivateShareDialog::onShareFailed(const ApiError& error)
+{
+    request_in_progress_ = false;
+    model_->shareOperationFailed(PrivateShareRequest::ADD_SHARE);
+    showWarning(tr("Share Operation Failed: %1").arg(error.toString()));
+}
+
+void PrivateShareDialog::showWarning(const QString& msg)
+{
+    seafApplet->warningBox(msg, this);
+}
+
+SharedItemsHeadView::SharedItemsHeadView(QWidget* parent)
+    : QHeaderView(Qt::Horizontal, parent)
+{
+    setDefaultAlignment(Qt::AlignLeft);
+    setStretchLastSection(false);
+    setCascadingSectionResizes(true);
+    setHighlightSections(false);
+    setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    setSectionResizeMode(QHeaderView::ResizeToContents);
+#else
+    setResizeMode(QHeaderView::ResizeToContents);
+#endif
+}
+
+QSize SharedItemsHeadView::sectionSizeFromContents(int index) const
+{
+    QSize size = QHeaderView::sectionSizeFromContents(index);
+    SharedItemsTableView* table = (SharedItemsTableView*)parent();
+    SharedItemsTableModel* model =
+        (SharedItemsTableModel*)(table->sourceModel());
+    if (model) {
+        size.setWidth(index == COLUMN_NAME ? model->nameColumnWidth()
+                                           : kPermissionColumnWidth);
+    }
+    return size;
+}
+
+SharedItemsTableView::SharedItemsTableView(QWidget* parent)
+    : QTableView(parent), source_model_(0)
+{
+    setHorizontalHeader(new SharedItemsHeadView(this));
+    verticalHeader()->hide();
+
+    setSelectionBehavior(QAbstractItemView::SelectRows);
+    setSelectionMode(QAbstractItemView::SingleSelection);
+
+    setMouseTracking(true);
+    setShowGrid(false);
+    setContentsMargins(0, 5, 0, 5);
+    // setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+    horizontalScrollBar()->close();
+}
+
+void SharedItemsTableView::setModel(QAbstractItemModel* model)
+{
+    QTableView::setModel(model);
+    source_model_ = qobject_cast<SharedItemsTableModel*>(model);
+}
+
+void SharedItemsTableView::resizeEvent(QResizeEvent* event)
+{
+    QTableView::resizeEvent(event);
+    if (source_model_)
+        source_model_->onResize(event->size());
+}
+
+
+SharedItemsTableModel::SharedItemsTableModel(ShareType share_type,
+                                             QObject* parent)
+    : QAbstractTableModel(parent),
+      share_type_(share_type),
+      name_column_width_(kNameColumnWidth)
+{
+}
+
+
+int SharedItemsTableModel::columnCount(const QModelIndex& parent) const
+{
+    return MAX_COLUMN;
+}
+
+int SharedItemsTableModel::rowCount(const QModelIndex& parent) const
+{
+    return share_type_ == SHARE_TO_USER ? user_shares_.size()
+                                        : group_shares_.size();
+}
+
+QVariant SharedItemsTableModel::data(const QModelIndex& index, int role) const
+{
+    if (!index.isValid()) {
+        return QVariant();
+    }
+
+    if (role != Qt::DisplayRole && role != Qt::EditRole &&
+        role != Qt::SizeHintRole && role != Qt::ToolTipRole) {
+        return QVariant();
+    }
+
+    int row = index.row(), column = index.column();
+
+    if (role == Qt::EditRole && column != COLUMN_PERMISSION) {
+        return QVariant();
+    }
+
+    if (role == Qt::ToolTipRole) {
+        if (column == COLUMN_PERMISSION) {
+            return tr("Click to edit");
+        }
+        else {
+            if (isGroupShare()) {
+                const GroupShareInfo& info = group_shares_[row];
+                if (!info.group.owner.isEmpty()) {
+                    return tr("Created by %1").arg(info.group.owner);
+                }
+            }
+            else {
+                return user_shares_[row].user.getDisplayEmail();
+            }
+        }
+        return QVariant();
+    }
+
+    // DisplayRole
+
+    if (role == Qt::SizeHintRole) {
+        QSize qsize(0, kDefaultColumnHeight);
+        if (column == COLUMN_NAME) {
+            qsize.setWidth(name_column_width_);
+        }
+        else {
+            qsize.setWidth(kPermissionColumnWidth);
+        }
+        return qsize;
+    }
+
+    if (isGroupShare()) {
+        if (row >= group_shares_.size()) {
+            return QVariant();
+        }
+        const GroupShareInfo& info = group_shares_[row];
+
+        if (column == COLUMN_NAME) {
+            return info.group.name;
+        }
+        else if (column == COLUMN_PERMISSION) {
+            if (role == Qt::DisplayRole) {
+                return info.permission == READ_WRITE ? tr("Read Write")
+                                                     : tr("Read Only");
+            }
+            else {
+                return info.permission == READ_WRITE ? 0 : 1;
+            }
+        }
+    }
+    else {
+        if (row >= user_shares_.size()) {
+            return QVariant();
+        }
+        const UserShareInfo& info = user_shares_[row];
+
+        if (column == COLUMN_NAME) {
+            // Here the `info.user.name` field should always be non-empty:
+            // - If the share is an existing share (fetched at dialog
+            //   initialization), the the user name is returned in the api
+            //   request.
+            // - If the share is newly added, the user must be chosen from the
+            //   completion popup, which means we have full information of the
+            //   user.
+            return info.user.name;
+        }
+        else if (column == COLUMN_PERMISSION) {
+            if (role == Qt::DisplayRole) {
+                return info.permission == READ_WRITE ? tr("Read Write")
+                                                     : tr("Read Only");
+            }
+            else {
+                return info.permission == READ_WRITE ? 0 : 1;
+            }
+        }
+    }
+
+    return QVariant();
+}
+
+void SharedItemsTableModel::onResize(const QSize& size)
+{
+    name_column_width_ = size.width() - kPermissionColumnWidth;
+    if (rowCount() != 0) {
+        emit dataChanged(index(0, COLUMN_NAME),
+                         index(rowCount() - 1, COLUMN_NAME));
+    }
+}
+
+bool SharedItemsTableModel::isGroupShare() const
+{
+    return share_type_ == SHARE_TO_GROUP;
+}
+
+QVariant SharedItemsTableModel::headerData(int section,
+                                           Qt::Orientation orientation,
+                                           int role) const
+{
+    if (orientation == Qt::Vertical) {
+        return QVariant();
+    }
+
+    if (section == COLUMN_NAME) {
+        if (role == Qt::DisplayRole) {
+            return isGroupShare() ? tr("Group") : tr("User");
+        }
+    }
+    else if (section == COLUMN_PERMISSION) {
+        if (role == Qt::DisplayRole) {
+            return tr("Permission");
+        }
+    }
+
+
+    return QVariant();
+}
+
+
+void SharedItemsTableModel::setShareInfo(
+    const QList<GroupShareInfo>& group_shares,
+    const QList<UserShareInfo>& user_shares)
+{
+    beginResetModel();
+    group_shares_ = group_shares;
+    user_shares_ = user_shares;
+    endResetModel();
+}
+
+void SharedItemsTableModel::addNewShareInfo(UserShareInfo newinfo)
+{
+    previous_user_shares_ = user_shares_;
+    beginResetModel();
+    bool exists = false;
+    for (int i = 0; i < user_shares_.size(); i++) {
+        UserShareInfo& info = user_shares_[i];
+        if (info.user == newinfo.user) {
+            exists = true;
+            info.permission = newinfo.permission;
+        }
+    }
+    if (!exists) {
+        user_shares_.prepend(newinfo);
+    }
+    endResetModel();
+}
+
+void SharedItemsTableModel::addNewShareInfo(GroupShareInfo newinfo)
+{
+    previous_group_shares_ = group_shares_;
+    beginResetModel();
+    bool exists = false;
+    for (int i = 0; i < group_shares_.size(); i++) {
+        GroupShareInfo& info = group_shares_[i];
+        if (info.group.id == newinfo.group.id) {
+            exists = true;
+            info.permission = newinfo.permission;
+        }
+    }
+    if (!exists) {
+        group_shares_.prepend(newinfo);
+    }
+    endResetModel();
+}
+
+bool SharedItemsTableModel::shareExists(int group_id)
+{
+    foreach (const GroupShareInfo& info, group_shares_) {
+        if (info.group.id == group_id) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool SharedItemsTableModel::shareExists(const SeafileUser& user)
+{
+    foreach (const UserShareInfo& info, user_shares_) {
+        if (info.user == user) {
+            return true;
+        }
+    }
+    return false;
+}
+
+GroupShareInfo SharedItemsTableModel::shareInfo(int group_id)
+{
+    foreach (const GroupShareInfo& info, group_shares_) {
+        if (info.group.id == group_id) {
+            return info;
+        }
+    }
+    return GroupShareInfo();
+}
+
+UserShareInfo SharedItemsTableModel::shareInfo(const SeafileUser& user)
+{
+    foreach (const UserShareInfo& info, user_shares_) {
+        if (info.user == user) {
+            return info;
+        }
+    }
+    return UserShareInfo();
+}
+
+Qt::ItemFlags SharedItemsTableModel::flags(const QModelIndex& index) const
+{
+    if (!index.isValid())
+        return Qt::ItemIsEnabled;
+
+    if (index.column() == COLUMN_PERMISSION) {
+        return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
+    }
+    else {
+        return QAbstractItemModel::flags(index);
+    }
+}
+
+bool SharedItemsTableModel::removeRows(int row,
+                                       int count,
+                                       const QModelIndex& parent)
+{
+    beginRemoveRows(parent, row, row);
+    if (isGroupShare()) {
+        group_shares_.removeAt(row);
+    }
+    else {
+        user_shares_.removeAt(row);
+    }
+    endRemoveRows();
+    return true;
+}
+
+bool SharedItemsTableModel::setData(const QModelIndex& index,
+                                    const QVariant& value,
+                                    int role)
+{
+    PrivateShareDialog* dialog = (PrivateShareDialog*)QObject::parent();
+    if (dialog->requestInProgress()) {
+        dialog->showWarning(tr("The previous operation is still in progres"));
+        return false;
+    }
+    if (!index.isValid() || role != Qt::EditRole) {
+        return false;
+    }
+    int permission = value.toInt();
+    int row = index.row();
+    if (isGroupShare()) {
+        previous_group_shares_ = group_shares_;
+        GroupShareInfo& info = group_shares_[row];
+        if (permission == 3) {
+            emit removeShareItem(info.group.id, info.permission);
+            removed_group_share_ = info;
+            removeRows(row, 1);
+        }
+        else if (permission == info.permission) {
+        }
+        else {
+            emit updateShareItem(info.group.id, (SharePermission)permission);
+            info.permission =
+                info.permission == READ_ONLY ? READ_WRITE : READ_ONLY;
+            emit dataChanged(index, index);
+        }
+    }
+    else {
+        previous_user_shares_ = user_shares_;
+        UserShareInfo& info = user_shares_[row];
+        if (permission == 3) {
+            emit removeShareItem(info.user, info.permission);
+            removed_user_share_ = info;
+            removeRows(row, 1);
+        }
+        else if (permission == info.permission) {
+        }
+        else {
+            emit updateShareItem(info.user, (SharePermission)permission);
+            info.permission =
+                info.permission == READ_ONLY ? READ_WRITE : READ_ONLY;
+            emit dataChanged(index, index);
+        }
+    }
+
+    return true;
+}
+
+void SharedItemsTableModel::shareOperationSuccess()
+{
+}
+
+void SharedItemsTableModel::shareOperationFailed(
+    PrivateShareRequest::ShareOperation op)
+{
+    beginResetModel();
+    if (isGroupShare()) {
+        group_shares_ = previous_group_shares_;
+    }
+    else {
+        user_shares_ = previous_user_shares_;
+    }
+    endResetModel();
+}
+
+QModelIndex SharedItemsTableModel::getIndexByGroup(int group_id) const
+{
+    for (int i = 0; i < group_shares_.size(); i++) {
+        if (group_shares_[i].group.id == group_id) {
+            return index(i, 0);
+        }
+    }
+    return index(0, 0);
+}
+
+QModelIndex SharedItemsTableModel::getIndexByUser(const SeafileUser& user) const
+{
+    for (int i = 0; i < user_shares_.size(); i++) {
+        if (user_shares_[i].user == user) {
+            return index(i, 0);
+        }
+    }
+    return index(0, 0);
+}
+
+SharedItemDelegate::SharedItemDelegate(QObject* parent)
+    : QStyledItemDelegate(parent)
+{
+}
+
+QWidget* SharedItemDelegate::createEditor(QWidget* parent,
+                                          const QStyleOptionViewItem& option,
+                                          const QModelIndex& index) const
+{
+    QComboBox* combobox = new QComboBox(parent);
+    combobox->addItem(tr("Read Write"));
+    combobox->addItem(tr("Read Only"));
+    combobox->insertSeparator(2);
+    combobox->addItem(tr("Remove Share"));
+
+    connect(combobox, SIGNAL(currentIndexChanged(int)),
+            this, SLOT(oncurrentIndexChanged()));
+
+    return combobox;
+}
+
+void SharedItemDelegate::setEditorData(QWidget* editor,
+                                       const QModelIndex& index) const
+{
+    int value = index.model()->data(index, Qt::EditRole).toInt();
+
+    QComboBox* combobox = static_cast<QComboBox*>(editor);
+    combobox->setCurrentIndex(value);
+}
+
+void SharedItemDelegate::setModelData(QWidget* editor,
+                                      QAbstractItemModel* model,
+                                      const QModelIndex& index) const
+{
+    QComboBox* combobox = static_cast<QComboBox*>(editor);
+    model->setData(index, combobox->currentIndex(), Qt::EditRole);
+}
+
+void SharedItemDelegate::updateEditorGeometry(
+    QWidget* editor,
+    const QStyleOptionViewItem& option,
+    const QModelIndex& index) const
+{
+    QComboBox* combobox = static_cast<QComboBox*>(editor);
+    combobox->setGeometry(option.rect);
+    // combobox->showPopup();
+}
+
+void SharedItemDelegate::paint(QPainter* painter,
+                               const QStyleOptionViewItem& option,
+                               const QModelIndex& index) const
+{
+    const SharedItemsTableModel* model =
+        static_cast<const SharedItemsTableModel*>(index.model());
+
+    QRect option_rect = option.rect;
+    bool selected = false;
+    // draw item's background
+    painter->save();
+    if (option.state & QStyle::State_Selected) {
+        painter->fillRect(option_rect, kSelectedItemBackgroundcColor);
+        selected = true;
+    }
+    else
+        painter->fillRect(option_rect, kItemBackgroundColor);
+    painter->restore();
+
+    // draw item's border for the first row only
+    static const QPen borderPen(kItemBottomBorderColor, 1);
+    // if (index.row() == 0) {
+    //     painter->save();
+    //     painter->setPen(borderPen);
+    //     painter->drawLine(option_rect.topLeft(), option_rect.topRight());
+    //     painter->restore();
+    // }
+    // draw item's border under the bottom
+    painter->save();
+    painter->setPen(borderPen);
+    painter->drawLine(option_rect.bottomLeft(), option_rect.bottomRight());
+    painter->restore();
+
+    QPoint text_pos(kMarginLeft + kPadding, kMarginTop + kPadding);
+    text_pos += option.rect.topLeft();
+
+    QSize size = model->data(index, Qt::SizeHintRole).value<QSize>();
+    QString text = model->data(index, Qt::DisplayRole).value<QString>();
+    QFont font = model->data(index, Qt::FontRole).value<QFont>();
+    QRect text_rect(text_pos, size);
+    painter->save();
+    painter->setPen(kItemColor);
+    painter->setFont(font);
+    painter->drawText(text_rect,
+                      Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, text,
+                      &text_rect);
+    painter->restore();
+
+    if (selected && index.column() == COLUMN_PERMISSION) {
+        int h = option.rect.height();
+        QPoint indicator_pos = option.rect.bottomRight() -
+                               QPoint(40, h - (h - kIndicatorIconHeight) / 2);
+        indicator_pos.setX(text_rect.topRight().x() +
+                           kMarginBetweenPermissionAndIndicator);
+        QRect indicator_rect(indicator_pos,
+                             QSize(kIndicatorIconWidth, kIndicatorIconHeight));
+
+        QPainterPath path;
+        path.moveTo(indicator_rect.topLeft());
+        path.lineTo(indicator_rect.topRight());
+        path.lineTo(indicator_rect.bottomRight() -
+                    QPoint((indicator_rect.width() / 2), 0));
+        path.lineTo(indicator_rect.topLeft());
+
+        painter->save();
+        painter->setRenderHint(QPainter::Antialiasing);
+        painter->setRenderHint(QPainter::HighQualityAntialiasing);
+        painter->fillPath(path, QBrush(kItemColor));
+        painter->restore();
+    }
+}
+
+void SharedItemDelegate::oncurrentIndexChanged()
+{
+    QComboBox* combobox = static_cast<QComboBox*>(sender());
+    emit commitData(combobox);
+}
diff --git a/src/ui/private-share-dialog.h b/src/ui/private-share-dialog.h
new file mode 100644 (file)
index 0000000..4cbcbdb
--- /dev/null
@@ -0,0 +1,245 @@
+#ifndef SEAFILE_CLIENT_UI_PRIVATE_SHARE_DIALOG_H
+#define SEAFILE_CLIENT_UI_PRIVATE_SHARE_DIALOG_H
+
+#include <QUrl>
+
+#include <QAbstractTableModel>
+#include <QCompleter>
+#include <QDialog>
+#include <QHash>
+#include <QScopedPointer>
+#include <QSet>
+#include <QStringList>
+#include <QStyledItemDelegate>
+#include <QTableView>
+#include <QHeaderView>
+#include "ui_private-share-dialog.h"
+
+#include "account.h"
+#include "api/contact-share-info.h"
+#include "api/requests.h"
+#include "user-name-completer.h"
+
+#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
+// only available in qt 5.0+
+#define Q_DECL_OVERRIDE
+#endif
+
+
+class QResizeEvent;
+
+class SharedItemsTableView;
+class SharedItemsTableModel;
+
+class PrivateShareDialog : public QDialog, public Ui::PrivateShareDialog
+{
+    Q_OBJECT
+public:
+    PrivateShareDialog(const Account& account,
+                       const QString& repo_id,
+                       const QString& repo_name,
+                       const QString& path,
+                       bool to_group,
+                       QWidget* parent);
+
+    bool requestInProgress() const
+    {
+        return request_in_progress_;
+    }
+    void showWarning(const QString& msg);
+
+public slots:
+    void onUpdateShareItem(int group_id, SharePermission permission);
+    void onUpdateShareItem(const SeafileUser& email, SharePermission permission);
+    void onRemoveShareItem(int group_id, SharePermission permission);
+    void onRemoveShareItem(const SeafileUser& user, SharePermission permission);
+
+private slots:
+    void selectFirstRow();
+    void onNameInputEdited();
+    void onShareSuccess();
+    void onShareFailed(const ApiError& error);
+    void onUpdateShareSuccess();
+    void onUpdateShareFailed(const ApiError& error);
+    void onRemoveShareSuccess();
+    void onRemoveShareFailed(const ApiError& error);
+    void onFetchGroupsSuccess(const QList<SeafileGroup>& groups);
+    void onFetchContactsFailed(const ApiError& error);
+    void onOkBtnClicked();
+    void onGetSharedItemsSuccess(const QList<GroupShareInfo>& group_shares,
+                                 const QList<UserShareInfo>& user_shares);
+    void onGetSharedItemsFailed(const ApiError& error);
+    void onUserNameChoosed();
+
+private:
+    void createTable();
+    void fetchGroupsForCompletion();
+    void getExistingShardItems();
+    bool validateInputs();
+    void toggleInputs(bool enabled);
+    void enableInputs();
+    void disableInputs();
+    SharePermission currentPermission();
+    SeafileGroup findGroup(const QString& name);
+    QLineEdit* lineEdit() const
+    {
+        return to_group_ ? groupname_input_->lineEdit() : username_input_;
+    }
+    void updateUsersCompletion(const QList<SeafileUser>& users);
+
+    Account account_;
+    QString repo_id_;
+    QString repo_name_;
+    QString path_;
+    bool to_group_;
+
+    QHash<int, SeafileGroup> groups_by_id_;
+
+    // A (pattern, possible users for completion) multi map.
+    struct CachedUsersEntry {
+        QSet<SeafileUser> users;
+        qint64 ts;
+    };
+
+    SharedItemsTableView* table_;
+    SharedItemsTableModel* model_;
+
+    QScopedPointer<PrivateShareRequest, QScopedPointerDeleteLater> request_;
+    QScopedPointer<FetchGroupsRequest, QScopedPointerDeleteLater> fetch_groups_request_;
+    QScopedPointer<GetPrivateShareItemsRequest, QScopedPointerDeleteLater> get_shared_items_request_;
+    QScopedPointer<SeafileUserNameCompleter, QScopedPointerDeleteLater> user_name_completer_;
+
+    bool request_in_progress_;
+
+    QLineEdit* username_input_;
+    QComboBox* groupname_input_;
+};
+
+class SharedItemsHeadView : public QHeaderView
+{
+    Q_OBJECT
+public:
+    SharedItemsHeadView(QWidget* parent = 0);
+
+    QSize sectionSizeFromContents(int index) const Q_DECL_OVERRIDE;
+};
+
+class SharedItemsTableView : public QTableView
+{
+    Q_OBJECT
+public:
+    SharedItemsTableView(QWidget* parent = 0);
+
+    void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE;
+
+    void setModel(QAbstractItemModel* model) Q_DECL_OVERRIDE;
+
+    SharedItemsTableModel* sourceModel()
+    {
+        return source_model_;
+    }
+
+private:
+    SharedItemsTableModel* source_model_;
+};
+
+class SharedItemsTableModel : public QAbstractTableModel
+{
+    Q_OBJECT
+public:
+    SharedItemsTableModel(ShareType share_type, QObject* parent = 0);
+
+    void setShareInfo(const QList<GroupShareInfo>& group_shares,
+                      const QList<UserShareInfo>& user_shares);
+
+    void addNewShareInfo(UserShareInfo info);
+    void addNewShareInfo(GroupShareInfo info);
+
+    bool shareExists(int group_id);
+    bool shareExists(const SeafileUser& user);
+
+    GroupShareInfo shareInfo(int group_id);
+    UserShareInfo shareInfo(const SeafileUser& user);
+
+    void shareOperationSuccess();
+    void shareOperationFailed(PrivateShareRequest::ShareOperation op);
+
+    int rowCount(const QModelIndex& parent = QModelIndex()) const
+        Q_DECL_OVERRIDE;
+    int columnCount(const QModelIndex& parent = QModelIndex()) const
+        Q_DECL_OVERRIDE;
+    QVariant data(const QModelIndex& index,
+                  int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+    Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE;
+    bool setData(const QModelIndex& index,
+                 const QVariant& value,
+                 int role) Q_DECL_OVERRIDE;
+    bool removeRows(int row,
+                    int count,
+                    const QModelIndex& parent = QModelIndex()) Q_DECL_OVERRIDE;
+
+    QVariant headerData(int section,
+                        Qt::Orientation orientation,
+                        int role) const Q_DECL_OVERRIDE;
+
+    int nameColumnWidth() const
+    {
+        return name_column_width_;
+    }
+
+    QModelIndex getIndexByGroup(int group_id) const;
+    QModelIndex getIndexByUser(const SeafileUser& user) const;
+signals:
+    void updateShareItem(int group_id, SharePermission permission);
+    void updateShareItem(const SeafileUser& user, SharePermission permission);
+    void removeShareItem(int group_id, SharePermission permission);
+    void removeShareItem(const SeafileUser& user, SharePermission permission);
+
+public slots:
+    void onResize(const QSize& size);
+
+private:
+    bool isGroupShare() const;
+
+    QList<UserShareInfo> user_shares_, previous_user_shares_;
+    QList<GroupShareInfo> group_shares_, previous_group_shares_;
+
+    ShareType share_type_;
+    int name_column_width_;
+
+    GroupShareInfo removed_group_share_;
+    UserShareInfo removed_user_share_;
+};
+
+
+class SharedItemDelegate : public QStyledItemDelegate
+{
+    Q_OBJECT
+
+public:
+    SharedItemDelegate(QObject* parent = 0);
+
+    QWidget* createEditor(QWidget* parent,
+                          const QStyleOptionViewItem& option,
+                          const QModelIndex& index) const Q_DECL_OVERRIDE;
+
+    void setEditorData(QWidget* editor,
+                       const QModelIndex& index) const Q_DECL_OVERRIDE;
+    void setModelData(QWidget* editor,
+                      QAbstractItemModel* model,
+                      const QModelIndex& index) const Q_DECL_OVERRIDE;
+
+    void updateEditorGeometry(QWidget* editor,
+                              const QStyleOptionViewItem& option,
+                              const QModelIndex& index) const Q_DECL_OVERRIDE;
+
+    void paint(QPainter* painter,
+               const QStyleOptionViewItem& option,
+               const QModelIndex& index) const Q_DECL_OVERRIDE;
+
+private slots:
+    void oncurrentIndexChanged();
+};
+
+
+#endif // SEAFILE_CLIENT_UI_PRIVATE_SHARE_DIALOG_H
diff --git a/src/ui/proxy-style.cpp b/src/ui/proxy-style.cpp
new file mode 100644 (file)
index 0000000..ec01d67
--- /dev/null
@@ -0,0 +1,29 @@
+#include <cstdio>
+#include <QStyleOptionTab>
+
+#include "proxy-style.h"
+
+void SeafileProxyStyle::drawControl(ControlElement element,
+                                    const QStyleOption * option,
+                                    QPainter * painter,
+                                    const QWidget * widget) const
+{
+
+    if (element == CE_TabBarTabLabel) {
+        // printf ("[draw tab label] name is %s\n", widget->objectName().toUtf8().data());
+        if (const QStyleOptionTab *tb = qstyleoption_cast<const QStyleOptionTab *>(option)) {
+            if (tb->state & State_HasFocus) {
+                QStyleOptionTab t(*tb);
+                t.state = t.state ^ State_HasFocus;
+                QProxyStyle::drawControl(element, &t, painter, widget);
+                return;
+            }
+        }
+    }
+
+    if (element == CE_TabBarTab) {
+        // printf ("[draw tab] name is %s\n", widget->objectName().toUtf8().data());
+    }
+
+    QProxyStyle::drawControl(element, option, painter, widget);
+}
diff --git a/src/ui/proxy-style.h b/src/ui/proxy-style.h
new file mode 100644 (file)
index 0000000..ffd8075
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SEAFILE_CLEINT_PROXY_STYLE
+#define SEAFILE_CLEINT_PROXY_STYLE
+
+#include <QProxyStyle>
+
+class QStyleOption;
+class QPainter;
+class QWidget;
+
+/**
+ * Use a custom proxy style to remove the border of tabbar text when selected
+ * See http://stackoverflow.com/questions/7492080/styling-the-text-outline-in-qts-tabs
+ */
+class SeafileProxyStyle: public QProxyStyle {
+public:
+    virtual void drawControl (ControlElement element, const QStyleOption * option,
+                              QPainter * painter, const QWidget * widget = 0) const;
+};
+
+#endif // SEAFILE_CLEINT_PROXY_STYLE
diff --git a/src/ui/repo-detail-dialog.cpp b/src/ui/repo-detail-dialog.cpp
new file mode 100644 (file)
index 0000000..c42ebc3
--- /dev/null
@@ -0,0 +1,138 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QDir>
+#include <QTimer>
+
+#include "utils/utils.h"
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "api/requests.h"
+#include "rpc/rpc-client.h"
+#include "rpc/clone-task.h"
+#include "rpc/local-repo.h"
+#include "utils/utils.h"
+
+#include "repo-detail-dialog.h"
+
+namespace {
+
+
+const int kRefrshRepoStatusInterval = 1000; // 1s
+
+} // namespace
+
+
+RepoDetailDialog::RepoDetailDialog(const ServerRepo &repo, QWidget *parent)
+    : QDialog(parent),
+      repo_(repo)
+{
+    setupUi(this);
+    setWindowTitle(tr("Library \"%1\"").arg(repo.name));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+    setWindowIcon(QIcon(":/images/seafile.png"));
+
+    mTimeLabel->setText(translateCommitTime(repo.mtime));
+    mOwnerLabel->setText(repo.owner);
+    mSizeLabel->setText(readableFileSize(repo.size));
+
+    LocalRepo lrepo;
+    seafApplet->rpcClient()->getLocalRepo(repo.id, &lrepo);
+    if (lrepo.isValid()) {
+        lpathLabel->setVisible(true);
+        mLpathLabel->setVisible(true);
+        mLpathLabel->setText(QDir::toNativeSeparators(lrepo.worktree));
+        if (lrepo.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+            mStatus->setText(lrepo.sync_error_str);
+        } else {
+            mStatus->setText(lrepo.sync_state_str);
+        }
+    } else {
+        mStatus->setText(tr("This library is not downloaded yet"));
+        lpathLabel->setVisible(false);
+        mLpathLabel->setVisible(false);
+    }
+
+    mRepoIcon->setPixmap(repo_.getPixmap());
+    mRepoName->setText(repo_.name);
+    #if defined(Q_OS_MAC)
+    layout()->setContentsMargins(8, 9, 9, 4);
+    layout()->setSpacing(5);
+    #endif
+
+    resize(sizeHint());
+    updateRepoStatus();
+
+    refresh_timer_ = new QTimer(this);
+    connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(updateRepoStatus()));
+    refresh_timer_->start(kRefrshRepoStatusInterval);
+}
+
+void RepoDetailDialog::updateRepoStatus()
+{
+    LocalRepo r;
+    QString text;
+    seafApplet->rpcClient()->getLocalRepo(repo_.id, &r);
+    if (r.isValid()) {
+        if (r.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+            text = "<p style='color:red'>" + tr("Error: ") + r.sync_error_str + "</p>";
+        } else {
+            text = r.sync_state_str;
+            if (r.sync_state == LocalRepo::SYNC_STATE_ING) {
+                // add transfer rate and finished percent
+                int rate, percent;
+                if (seafApplet->rpcClient()->getRepoTransferInfo(repo_.id, &rate, &percent) == 0) {
+                    text += ", " + QString::number(percent) + "%, " +  QString("%1 kB/s").arg(rate / 1024);
+                }
+            }
+        }
+
+        int sync_interval = 0;
+        QString interval_string;
+        if (seafApplet->rpcClient()->getRepoProperty(r.id, "sync-interval", &interval_string) == 0) {
+            sync_interval = interval_string.toInt();
+            if (sync_interval > 0) {
+                mSyncInterval->setText(tr("every %1 seconds").arg(sync_interval));
+            } else {
+                mSyncIntervalLabel->hide();
+                mSyncInterval->hide();
+            }
+        }
+
+    } else {
+        std::vector<CloneTask> tasks;
+        seafApplet->rpcClient()->getCloneTasks(&tasks);
+
+        CloneTask task;
+
+        if (!tasks.empty()) {
+            for (size_t i = 0; i < tasks.size(); ++i) {
+                CloneTask clone_task = tasks[i];
+                if (clone_task.repo_id == repo_.id) {
+                    task = clone_task;
+                    break;
+                }
+            }
+        }
+
+        if (task.isValid() && task.isDisplayable()) {
+            if (task.error_str.length() > 0) {
+                text = task.error_str;
+            } else {
+                text = task.state_str;
+            }
+        } else {
+            text = tr("This library is not downloaded yet");
+        }
+
+        mSyncIntervalLabel->hide();
+        mSyncInterval->hide();
+    }
+
+    mStatus->setText(text);
+}
diff --git a/src/ui/repo-detail-dialog.h b/src/ui/repo-detail-dialog.h
new file mode 100644 (file)
index 0000000..f827947
--- /dev/null
@@ -0,0 +1,26 @@
+#include <QDialog>
+#include <QUrl>
+#include <QString>
+
+#include "ui_repo-detail-dialog.h"
+#include "api/server-repo.h"
+#include "rpc/local-repo.h"
+
+class QTimer;
+
+class RepoDetailDialog : public QDialog,
+                         public Ui::RepoDetailDialog
+{
+    Q_OBJECT
+public:
+    RepoDetailDialog(const ServerRepo &repo, QWidget *parent=0);
+
+private slots:
+    void updateRepoStatus();
+
+private:
+    Q_DISABLE_COPY(RepoDetailDialog);
+
+    ServerRepo repo_;
+    QTimer *refresh_timer_;
+};
diff --git a/src/ui/repo-item-delegate.cpp b/src/ui/repo-item-delegate.cpp
new file mode 100644 (file)
index 0000000..20998ca
--- /dev/null
@@ -0,0 +1,552 @@
+#include <QPainter>
+#include <QApplication>
+#include <QPixmap>
+#include <QToolTip>
+#include <QSortFilterProxyModel>
+
+#include "utils/utils.h"
+#include "utils/paint-utils.h"
+#include "seafile-applet.h"
+#include "settings-mgr.h"
+#include "api/server-repo.h"
+#include "repo-item.h"
+#include "repo-tree-view.h"
+#include "repo-tree-model.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "account-mgr.h"
+#include "repo-service.h"
+#include "QtAwesome.h"
+
+#include "repo-item-delegate.h"
+
+namespace {
+
+/**
+            RepoName
+   RepoIcon          statusIcon
+            subtitle
+ */
+
+const int kMarginLeft = 16;
+const int kMarginRight = 5;
+const int kMarginTop = 5;
+const int kMarginBottom = 5;
+const int kPadding = 2;
+const int kRepoItemVerticalMargin = 13;
+const int kRepoCategoryVerticalMargin = 10;
+
+const int kRepoIconHeight = 36;
+const int kRepoIconWidth = 36;
+const int kRepoIconHeightAlpha = 24;
+const int kRepoIconWidthAlpha = 24;
+const int kRepoNameWidth = 175;
+const int kRepoNameHeight = 30;
+const int kRepoNameHeightAlpha = 20;
+const int kRepoDescriptionHeightAlpha = 14;
+const int kRepoStatusIconWidth = 24;
+const int kRepoStatusIconHeight = 24;
+const int kRepoStatusIconWidthAlpha = 16;
+const int kRepoStatusIconHeightAlpha = 16;
+
+const char *kRepoCategoryIndicatorColor = "#BBB";
+const int kRepoCategoryNameMaxWidth = 400;
+const int kRepoCategoryIndicatorWidth = 20;
+const int kRepoCategoryIndicatorHeight = 20;
+const int kMarginBetweenIndicatorAndName = 5;
+
+const int kMarginBetweenRepoIconAndName = 10;
+const int kMarginBetweenRepoNameAndStatus = 20;
+
+const char *kRepoNameColor = "#141414";
+const char *kRepoNameColorHighlighted = "#544D49";
+const char *kTimestampColor = "#AAAAAA";
+const char *kTimestampColorHighlighted = "#9D9B9A";
+const int kRepoNameFontSize = 14;
+const int kTimestampFontSize = 12;
+const int kRepoDescriptionFontSizeAlpha = 10;
+const int kRepoCategoryNameFontSize = 14;
+const int kRepoCategoryCountFontSize = 12;
+const int kRepoCategoryCountFontSizeAlpha = 14;
+const int kOwnerFontSize = 12;
+const int kOwnerFontSizeAlpha = 10;
+
+const char *kRepoItemBackgroundColorHighlightedAlpha = "#EFEEEE";
+const char *kRepoItemBackgroundColor = "white";
+const char *kRepoItemBackgroundColorDragMove = "#EFEEEE";
+
+const char *kRepoCategoryColor = "#747474";
+
+const char *kRepoCategoryBackgroundColor = "white";
+
+const int kRepoCategoryCountMarginRight = 10;
+const int kRepoCategoryCountMarginRightAlpha = 20;
+const char *kRepoCategoryCountColor = "#AAAAAA";
+
+static void showTooltip(const QString &text,
+                        QWidget *viewport,
+                        const QRect &rect,
+                        const QRect &small_rect)
+{
+    QPoint tool_tip_pos =
+        viewport->mapToGlobal(small_rect.center() + rect.topLeft());
+    QToolTip::showText(
+        tool_tip_pos, text, viewport, small_rect.translated(rect.topLeft()));
+}
+
+} // namespace
+
+RepoItemDelegate::RepoItemDelegate(QObject *parent)
+  : QStyledItemDelegate(parent)
+{
+}
+
+QSize RepoItemDelegate::sizeHint(const QStyleOptionViewItem &option,
+                                 const QModelIndex &index) const
+{
+    QStandardItem *item = getItem(index);
+    if (!item) {
+        return QStyledItemDelegate::sizeHint(option, index);
+    }
+
+    if (item->type() == REPO_ITEM_TYPE) {
+        return sizeHintForRepoItem(option, (const RepoItem *)item);
+    } else {
+        // return QStyledItemDelegate::sizeHint(option, index);
+        return sizeHintForRepoCategoryItem(option, (const RepoCategoryItem *)item);
+    }
+}
+
+QSize RepoItemDelegate::sizeHintForRepoItem(const QStyleOptionViewItem &option,
+                                            const RepoItem *item) const
+{
+
+    int width = kMarginLeft + kRepoIconWidthAlpha
+        + kMarginBetweenRepoIconAndName + kRepoNameWidth
+        + kMarginBetweenRepoNameAndStatus + kRepoStatusIconWidthAlpha
+        + kMarginRight + kPadding * 2;
+
+    // int height = kRepoIconHeightAlpha + kPadding * 2 + kMarginTop + kMarginBottom;
+    int height = kRepoIconHeightAlpha + kRepoItemVerticalMargin * 2;
+
+    // qDebug("width = %d, height = %d\n", width, height);
+
+    return QSize(width, height);
+}
+
+QSize RepoItemDelegate::sizeHintForRepoCategoryItem(const QStyleOptionViewItem &option,
+                                                    const RepoCategoryItem *item) const
+{
+    int width, height;
+
+    QFontMetrics qfm(changeFontSize(option.font, kRepoCategoryNameFontSize));
+    QSize size = qfm.size(0, item->name());
+
+    width = qMin(size.width(), kRepoCategoryIndicatorWidth)
+        + kMarginBetweenIndicatorAndName + kRepoCategoryNameMaxWidth;
+
+    // height = qMax(size.height(), kRepoCategoryIndicatorHeight) + kPadding;
+    height = qMax(size.height(), kRepoCategoryIndicatorHeight) + kRepoCategoryVerticalMargin * 2;
+
+    RepoTreeModel *model = (RepoTreeModel *)item->model();
+    model->repo_category_height = height;
+
+    // qDebug("width = %d, height = %d\n", width, height);
+
+    return QSize(width, height);
+}
+
+
+void RepoItemDelegate::paint(QPainter *painter,
+                             const QStyleOptionViewItem& option,
+                             const QModelIndex& index) const
+{
+    QStandardItem *item = getItem(index);
+    if (!item) {
+        QStyledItemDelegate::paint(painter, option, index);
+        return;
+    }
+
+    if (item->type() == REPO_ITEM_TYPE) {
+        paintRepoItem(painter, option, (RepoItem *)item);
+    } else {
+        paintRepoCategoryItem(painter, option, (RepoCategoryItem *)item);
+    }
+
+    // fix for showing first category if hidden
+    RepoTreeView *view = static_cast<RepoTreeView*>(parent());
+    QModelIndex top_index = view->indexAt(QPoint(0, 0)).parent();
+    if (top_index.isValid()) {
+        if (option.rect.contains(QPoint(0, 0))) {
+            const RepoCategoryItem *category_item =
+                static_cast<RepoCategoryItem *>(getItem(top_index));
+            QStyleOptionViewItem category_option = option;
+            category_option.rect = QRect(0, 0, option.rect.width(),
+                                         sizeHintForRepoCategoryItem(option, category_item).height());
+            paintRepoCategoryItem(painter, category_option, category_item);
+        }
+    }
+}
+
+void RepoItemDelegate::paintRepoItem(QPainter *painter,
+                                     const QStyleOptionViewItem& option,
+                                     const RepoItem *item) const
+{
+    const ServerRepo& repo = item->repo();
+    QBrush backBrush;
+    bool selected = false;
+
+    RepoTreeModel *model = (RepoTreeModel *)item->model();
+    RepoTreeView *view = model->treeView();
+    QModelIndex index = ((QSortFilterProxyModel *)view->model())->mapFromSource(model->indexFromItem(item));
+    if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) {
+        backBrush = QColor(kRepoItemBackgroundColorHighlightedAlpha);
+        selected = true;
+    } else if (view->getCurrentDropTarget() == index) {
+        backBrush = QColor(kRepoItemBackgroundColorDragMove);
+    } else {
+        backBrush = QColor(kRepoItemBackgroundColor);
+    }
+
+    painter->save();
+    painter->fillRect(option.rect, backBrush);
+    painter->restore();
+
+    int indent_left = 0;
+    if (item->level() > 0) {
+        indent_left = kRepoCategoryIndicatorWidth + kMarginBetweenIndicatorAndName;
+    }
+
+    // Paint repo icon
+    QPoint repo_icon_pos(kMarginLeft + kPadding + indent_left, kRepoItemVerticalMargin);
+    repo_icon_pos += option.rect.topLeft();
+
+    // get the device pixel radio from current painter device
+    int scale_factor = 1;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    scale_factor = painter->device()->devicePixelRatio();
+#endif // QT5
+    QPixmap repo_icon = repo.getIcon().pixmap(QSize(kRepoIconWidthAlpha, kRepoIconHeightAlpha));
+
+    QRect repo_icon_rect(repo_icon_pos, QSize(kRepoIconWidthAlpha, kRepoIconHeightAlpha));
+    painter->save();
+    painter->drawPixmap(repo_icon_rect, repo_icon);
+    painter->restore();
+
+    // Paint repo name
+    int vertical_margin_between_icon_and_name = 0;
+#ifdef Q_OS_WIN32
+    vertical_margin_between_icon_and_name = -9;
+#else
+    vertical_margin_between_icon_and_name = -5;
+#endif
+    QPoint repo_name_pos = repo_icon_pos + QPoint(kRepoIconWidthAlpha + kMarginBetweenRepoIconAndName,
+                                                  vertical_margin_between_icon_and_name);
+    int repo_name_width = option.rect.width() - kRepoIconWidthAlpha - kMarginBetweenRepoIconAndName
+        - kRepoStatusIconWidthAlpha - kMarginBetweenRepoNameAndStatus
+        - kPadding * 2 - kMarginLeft - kMarginRight;
+    repo_name_width -= indent_left;
+    int repo_name_height = ::textHeightInFont(repo.name, changeFontSize(painter->font(), kRepoNameFontSize));
+    QRect repo_name_rect(repo_name_pos, QSize(repo_name_width, repo_name_height));
+    painter->save();
+    painter->setPen(QColor(selected ? kRepoNameColorHighlighted : kRepoNameColor));
+    painter->setFont(changeFontSize(painter->font(), kRepoNameFontSize));
+    painter->drawText(repo_name_rect,
+                      Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
+                      fitTextToWidth(repo.name, painter->font(), repo_name_width),
+                      &repo_name_rect);
+    painter->restore();
+
+    // Paint repo description
+    QString description;
+    const LocalRepo& r = item->localRepo();
+    if (r.isValid()) {
+        if (r.sync_state == LocalRepo::SYNC_STATE_ING) {
+            description = r.sync_state_str;
+            if (r.has_data_transfer) {
+                int rate, percent;
+                if (seafApplet->rpcClient()->getRepoTransferInfo(r.id, &rate, &percent) == 0) {
+                    description += ", " + QString::number(percent) + "%";
+                }
+            }
+        } else if (r.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+            description = r.getErrorString();
+        }
+    } else {
+        const CloneTask& task = item->cloneTask();
+        if (task.isValid() && task.isDisplayable()) {
+            if (task.error_str.length() > 0) {
+                description = task.error_str;
+            } else {
+                description = task.state_str;
+            }
+        }
+    }
+
+    if (description.isEmpty()) {
+        description = translateCommitTime(repo.mtime);
+    }
+    painter->save();
+    QPoint repo_desc_pos = repo_name_rect.bottomLeft() + QPoint(0, 5);
+    int repo_desc_height = ::textHeightInFont(description, changeFontSize(painter->font(), kRepoDescriptionFontSizeAlpha));
+    QRect repo_desc_rect(repo_desc_pos, QSize(repo_name_width, repo_desc_height));
+    painter->setFont(changeFontSize(painter->font(), kRepoDescriptionFontSizeAlpha));
+    painter->setPen(QColor(selected ? kTimestampColorHighlighted : kTimestampColor));
+    painter->drawText(repo_desc_rect,
+                      Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
+                      fitTextToWidth(description, painter->font(), repo_name_width),
+                      &repo_desc_rect);
+    painter->restore();
+
+    // Paint extra description
+    QString extra_description;
+    if (repo.isSubfolder()) {
+        ServerRepo parent_repo = RepoService::instance()->getRepo(repo.parent_repo_id);
+        extra_description = tr(", %1%2").arg(parent_repo.name).arg(repo.parent_path);
+    }
+    // Paint repo sharing owner for private share
+    if (static_cast<RepoCategoryItem*>(item->parent())->categoryIndex() ==
+        RepoTreeModel::CAT_INDEX_SHARED_REPOS)
+        extra_description += tr(", %1").arg(repo.owner.split('@').front());
+    if (!extra_description.isEmpty()) {
+        int width = option.rect.topRight().x() - 40 - repo_desc_rect.topRight().x();
+        if (width < 3)
+            width = 3;
+        int vertical_margin_between_desc_and_extra_desc = 0;
+#ifdef Q_OS_LINUX
+        vertical_margin_between_desc_and_extra_desc = 3;
+#endif
+        QPoint repo_owner_pos = repo_desc_rect.topRight() + QPoint(0, vertical_margin_between_desc_and_extra_desc);
+        int extra_desc_height = ::textHeightInFont(extra_description, changeFontSize(painter->font(), kOwnerFontSizeAlpha));
+        QRect repo_owner_rect(repo_owner_pos, QSize(width, extra_desc_height));
+
+        painter->save();
+        painter->setFont(changeFontSize(painter->font(), kOwnerFontSizeAlpha));
+        painter->setPen(QColor(selected ? kTimestampColorHighlighted : kTimestampColor));
+        painter->drawText(repo_owner_rect,
+                          Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
+                          fitTextToWidth(extra_description, painter->font(), width),
+                          &repo_owner_rect);
+
+        painter->restore();
+    }
+
+    // Paint repo status icon
+    QPoint status_icon_pos = option.rect.topRight() - QPoint(41, 0);
+    status_icon_pos.setY(option.rect.center().y() - (kRepoStatusIconHeightAlpha / 2));
+    QRect status_icon_rect(status_icon_pos, QSize(kRepoStatusIconWidthAlpha, kRepoStatusIconHeightAlpha));
+
+    QPixmap status_icon_pixmap = getSyncStatusIcon(item).pixmap(status_icon_rect.size());
+
+    painter->save();
+    painter->drawPixmap(status_icon_rect, status_icon_pixmap);
+    painter->restore();
+
+    // Update the metrics of this item
+    RepoItem::Metrics metrics;
+    QPoint shift(-option.rect.topLeft().x(), -option.rect.topLeft().y());
+    metrics.icon_rect = repo_icon_rect;
+    metrics.name_rect = repo_name_rect;
+    metrics.subtitle_rect = repo_desc_rect;
+    metrics.status_icon_rect = status_icon_rect;
+
+    metrics.icon_rect.translate(shift);
+    metrics.name_rect.translate(shift);
+    metrics.subtitle_rect.translate(shift);
+    metrics.status_icon_rect.translate(shift);
+
+    item->setMetrics(metrics);
+}
+
+void RepoItemDelegate::paintRepoCategoryItem(QPainter *painter,
+                                             const QStyleOptionViewItem& option,
+                                             const RepoCategoryItem *item) const
+{
+    QBrush backBrush = QColor(kRepoCategoryBackgroundColor);
+
+    painter->save();
+    painter->fillRect(option.rect, backBrush);
+    painter->restore();
+
+    // Paint the expand/collapse indicator
+    painter->save();
+
+    RepoTreeModel *model = (RepoTreeModel *)item->model();
+    RepoTreeView *view = model->treeView();
+    QModelIndex index = ((QSortFilterProxyModel *)view->model())->mapFromSource(model->indexFromItem(item));
+    bool expanded = view->isExpanded(index);
+    int indent_left = 0;
+    if (item->level() > 0) {
+        indent_left = kRepoCategoryIndicatorWidth + kMarginBetweenIndicatorAndName;
+    }
+
+    int repo_category_text_height = ::textHeightInFont(item->name(), changeFontSize(option.font, kRepoCategoryNameFontSize));
+    int vertical_padding_between_indicator_and_name = (repo_category_text_height - kRepoCategoryIndicatorHeight) / 2;
+
+    // [(size of category icon) - (size of repo icon)] / 2
+    int indicator_offset = (24 - 20) / 2;
+    QRect indicator_rect(option.rect.topLeft() +
+                         QPoint(kPadding + indicator_offset + kMarginLeft + indent_left,
+                                kRepoCategoryVerticalMargin + vertical_padding_between_indicator_and_name),
+                         QSize(kRepoCategoryIndicatorWidth, kRepoCategoryIndicatorHeight));
+    // get the device pixel radio from current painter device
+    int scale_factor = 1;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    scale_factor = painter->device()->devicePixelRatio();
+#endif // QT5
+
+    QIcon icon(expanded ? awesome->icon(icon_caret_down, kRepoCategoryIndicatorColor)
+                        : awesome->icon(icon_caret_right, kRepoCategoryIndicatorColor));
+    QPixmap icon_pixmap(icon.pixmap(QSize(kRepoCategoryIndicatorWidth, kRepoCategoryIndicatorWidth)));
+    painter->drawPixmap(indicator_rect, icon_pixmap);
+    painter->restore();
+
+    // Paint category name
+
+    // calculate the count of synced repos
+    int synced_repos = 0;
+    for (int i = 0; i < item->rowCount(); ++i) {
+        QStandardItem *child = item->child(i);
+        if (child->type() == REPO_ITEM_TYPE) {
+            RepoItem *repo_item = static_cast<RepoItem *>(child);
+            if (repo_item->localRepo().isValid())
+                ++synced_repos;
+        } else {
+            RepoCategoryItem *cat_item = static_cast<RepoCategoryItem *>(child);
+            for (int j = 0; j < cat_item->rowCount(); ++j) {
+                RepoItem *repo_item = static_cast<RepoItem *>(cat_item->child(j));
+                if (repo_item->localRepo().isValid())
+                    ++synced_repos;
+            }
+        }
+    }
+    const QString category_count_text = QString::number(synced_repos) + "/" + QString::number(item->matchedReposCount());
+    const int category_count_width = ::textWidthInFont(category_count_text, changeFontSize(option.font, kRepoCategoryCountFontSizeAlpha));
+
+    painter->save();
+
+    int right_shift = kMarginLeft + kRepoIconWidthAlpha + kMarginBetweenRepoIconAndName - kRepoCategoryIndicatorWidth - kMarginLeft;
+    QPoint category_name_pos = indicator_rect.topRight() +
+                               QPoint(right_shift - 1, - vertical_padding_between_indicator_and_name);
+    QRect category_name_rect(category_name_pos,
+                             option.rect.bottomRight() - QPoint(kPadding + category_count_width + kRepoCategoryCountMarginRightAlpha,
+                                                                kRepoCategoryVerticalMargin));
+    painter->setPen(QColor(kRepoCategoryColor));
+    painter->setFont(changeFontSize(option.font, kRepoCategoryNameFontSize));
+    painter->drawText(category_name_rect,
+                      Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
+                      fitTextToWidth(item->name(), painter->font(), category_name_rect.width()));
+    painter->restore();
+
+    // Paint category count
+    painter->save();
+    QPoint category_count_pos = option.rect.topRight() +
+                                QPoint(-category_count_width - kRepoCategoryCountMarginRightAlpha, 0);
+    category_count_pos.setY(category_name_pos.y());
+    QRect category_count_rect(category_count_pos,
+                              option.rect.bottomRight() - QPoint(kRepoCategoryCountMarginRightAlpha, kRepoCategoryVerticalMargin));
+    painter->setFont(changeFontSize(option.font, kRepoCategoryCountFontSizeAlpha));
+    painter->setPen(QColor(kRepoCategoryCountColor));
+    painter->drawText(category_count_rect,
+                      Qt::AlignLeft | Qt::AlignTop,
+                      category_count_text);
+    painter->restore();
+}
+
+QIcon RepoItemDelegate::getSyncStatusIcon(const RepoItem *item) const
+{
+    const QString prefix = ":/images/sync/";
+    const LocalRepo& repo = item->localRepo();
+    QString icon;
+    if (!repo.isValid()) {
+        icon = "cloud-unsynced";
+    } else if (!seafApplet->settingsManager()->autoSync()) {
+        icon = "pause";
+    } else {
+        switch (repo.sync_state) {
+        case LocalRepo::SYNC_STATE_DONE:
+            icon = "cloud-synced";
+            break;
+        case LocalRepo::SYNC_STATE_ING:
+            icon = "cloud-sync";
+            break;
+        case LocalRepo::SYNC_STATE_ERROR:
+            icon = "exclamation";
+            break;
+        case LocalRepo::SYNC_STATE_WAITING:
+            icon = "waiting";
+            break;
+        case LocalRepo::SYNC_STATE_DISABLED:
+            icon = "pause";
+            break;
+        case LocalRepo::SYNC_STATE_UNKNOWN:
+            icon = "question";
+            break;
+        case LocalRepo::SYNC_STATE_INIT:
+            // If the repo is in "sync init", we just display the previous
+            // icon.
+            icon = last_icon_map_.value(repo.id, "waiting");
+            break;
+        }
+    }
+
+    last_icon_map_[repo.id] = icon;
+
+    return QIcon(prefix + icon + ".png");
+}
+
+QStandardItem* RepoItemDelegate::getItem(const QModelIndex &index) const
+{
+    if (!index.isValid()) {
+        return NULL;
+    }
+    QSortFilterProxyModel *proxy = (QSortFilterProxyModel *)index.model();
+    RepoTreeModel *tree_model_ = (RepoTreeModel *)(proxy->sourceModel());
+    QStandardItem *item = tree_model_->itemFromIndex(proxy->mapToSource(index));
+    if (item->type() != REPO_ITEM_TYPE &&
+        item->type() != REPO_CATEGORY_TYPE) {
+        return NULL;
+    }
+    return item;
+}
+
+void RepoItemDelegate::showRepoItemToolTip(const RepoItem *item,
+                                           const QPoint& global_pos,
+                                           QWidget *viewport,
+                                           const QRect& rect) const
+{
+    const RepoItem::Metrics& metrics = item->metrics();
+
+    const QRect& status_icon_rect = metrics.status_icon_rect;
+    const QRect& subtitle_rect = metrics.subtitle_rect;
+
+    QPoint viewpos = viewport->mapFromGlobal(global_pos);
+    viewpos -= rect.topLeft();
+
+    if (status_icon_rect.contains(viewpos)) {
+        QString text = "<p style='white-space:pre'>";
+        const LocalRepo& local_repo = item->localRepo();
+        if (!local_repo.isValid()) {
+            text += tr("This library has not been downloaded");
+        } else {
+            if (local_repo.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+                text += local_repo.getErrorString();
+            } else {
+                text += local_repo.sync_state_str;
+            }
+        }
+        text += "</p>";
+
+        showTooltip(text, viewport, rect, status_icon_rect);
+
+    } else if (subtitle_rect.contains(viewpos)) {
+        QString text = "<p style='white-space:pre'>";
+        const LocalRepo& local_repo = item->localRepo();
+        if (local_repo.isValid() && local_repo.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+            text += local_repo.getErrorString();
+            text += "</p>";
+            showTooltip(text, viewport, rect, subtitle_rect);
+        }
+    }
+}
+
diff --git a/src/ui/repo-item-delegate.h b/src/ui/repo-item-delegate.h
new file mode 100644 (file)
index 0000000..ba832ed
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
+#define SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
+
+#include <QStyledItemDelegate>
+#include <QHash>
+
+class QStandardItem;
+class QModelIndex;
+class QWidget;
+
+class ServerRepo;
+class RepoItem;
+class RepoCategoryItem;
+
+class RepoItemDelegate : public QStyledItemDelegate {
+    Q_OBJECT
+public:
+    explicit RepoItemDelegate(QObject *parent=0);
+
+    void paint(QPainter *painter,
+               const QStyleOptionViewItem& option,
+               const QModelIndex& index) const;
+
+    QSize sizeHint(const QStyleOptionViewItem& option,
+                   const QModelIndex& index) const;
+
+    void showRepoItemToolTip(const RepoItem *item,
+                             const QPoint& global_pos,
+                             QWidget *viewport,
+                             const QRect& rect) const;
+
+private:
+    QStandardItem* getItem(const QModelIndex &index) const;
+    void paintRepoItem(QPainter *painter,
+                       const QStyleOptionViewItem& opt,
+                       const RepoItem *item) const;
+
+    void paintRepoCategoryItem(QPainter *painter,
+                               const QStyleOptionViewItem& opt,
+                               const RepoCategoryItem *item) const;
+
+    QSize sizeHintForRepoCategoryItem(const QStyleOptionViewItem &option,
+                                      const RepoCategoryItem *item) const;
+
+    QSize sizeHintForRepoItem(const QStyleOptionViewItem &option,
+                              const RepoItem *item) const;
+
+    QIcon getSyncStatusIcon(const RepoItem *item) const;
+
+    mutable QHash<QString, QString> last_icon_map_;
+};
+
+
+#endif // SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
diff --git a/src/ui/repo-item.cpp b/src/ui/repo-item.cpp
new file mode 100644 (file)
index 0000000..f7f19d8
--- /dev/null
@@ -0,0 +1,88 @@
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "repo-item.h"
+
+RepoItem::RepoItem(const ServerRepo& repo)
+    : SeafileRepoBaseItem(),
+      repo_(repo)
+{
+    setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+
+    LocalRepo local_repo;
+    seafApplet->rpcClient()->getLocalRepo(repo.id, &local_repo);
+    setLocalRepo(local_repo);
+
+    sync_now_clicked_ = false;
+}
+
+void RepoItem::setRepo(const ServerRepo& repo)
+{
+    repo_ = repo;
+}
+
+void RepoItem::setLocalRepo(const LocalRepo& repo)
+{
+    local_repo_ = repo;
+}
+
+bool RepoItem::repoDownloadable() const
+{
+    if (local_repo_.isValid()) {
+        return false;
+    }
+
+    if (!clone_task_.isValid()) {
+        return true;
+    }
+
+    QString state = clone_task_.state;
+    if (state == "canceled" || state == "error" || state == "done") {
+        return true;
+    }
+
+    return false;
+}
+
+QVariant RepoItem::data(int role) const
+{
+    if (role == Qt::DisplayRole) {
+        return repo_.name;
+    } else {
+        return QVariant();
+    }
+}
+
+RepoCategoryItem::RepoCategoryItem(int cat_index, const QString& name, int group_id)
+    : SeafileRepoBaseItem(),
+      cat_index_(cat_index),
+      name_(name),
+      group_id_(group_id),
+      matched_repos_(-1)
+{
+    setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+}
+
+QVariant RepoCategoryItem::data(int role) const
+{
+    if (role != Qt::DisplayRole) {
+        return QVariant();
+    }
+
+    return name_;
+}
+
+int RepoCategoryItem::matchedReposCount() const
+{
+    if (isGroupsRoot()) {
+        // This item is the groups root level.
+        int i, n = rowCount(), sum = 0;
+        for (i = 0; i < n; i++) {
+            RepoCategoryItem *group = (RepoCategoryItem *)child(i);
+            sum += group->matchedReposCount();
+        }
+        return sum;
+    }
+
+    // A normal group item.
+    return matched_repos_ >= 0 ? matched_repos_ : rowCount();
+}
diff --git a/src/ui/repo-item.h b/src/ui/repo-item.h
new file mode 100644 (file)
index 0000000..9422058
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef SEAFILE_CLIENT_REPO_ITEM_H
+#define SEAFILE_CLIENT_REPO_ITEM_H
+
+#include <QStandardItem>
+#include "api/server-repo.h"
+#include "rpc/local-repo.h"
+#include "rpc/clone-task.h"
+
+#define MY_REPOS "My Libraries"
+#define SHARED_REPOS "Shared Libraries"
+
+enum {
+    REPO_ITEM_TYPE = QStandardItem::UserType,
+    REPO_CATEGORY_TYPE
+};
+
+
+class SeafileRepoBaseItem : public QStandardItem
+{
+public:
+    SeafileRepoBaseItem() : level_(0){};
+
+    void setLevel(int level)
+    {
+        level_ = level;
+    }
+
+    int level() const
+    {
+        return level_;
+    }
+
+private:
+    int level_;
+};
+
+
+/**
+ * Represent a repo
+ */
+class RepoItem : public SeafileRepoBaseItem {
+public:
+    RepoItem(const ServerRepo& repo);
+
+    void setRepo(const ServerRepo& repo);
+    void setLocalRepo(const LocalRepo& repo);
+
+    virtual int type() const { return REPO_ITEM_TYPE; }
+
+    const ServerRepo& repo() const { return repo_; }
+    const LocalRepo& localRepo() const { return local_repo_; }
+
+    /**
+     * Although we don't use this in our custom delegate, we need to
+     * implemented it for our proxy filter model.
+     */
+    QVariant data(int role=Qt::UserRole + 1) const;
+
+    /**
+     * Every time the item is painted, we record the metrics of each part of
+     * the item on the screen. So later we the mouse click/hover the item, we
+     * can decide which part is hovered, and to do corresponding actions.
+     */
+    struct Metrics {
+        QRect icon_rect;
+        QRect name_rect;
+        QRect subtitle_rect;
+        QRect status_icon_rect;
+    };
+
+    void setMetrics(const Metrics& metrics) const { metrics_ = metrics; }
+    const Metrics& metrics() const { return metrics_; }
+
+    void setCloneTask(const CloneTask& task=CloneTask()) { clone_task_ = task; }
+    const CloneTask& cloneTask() const { return clone_task_; }
+
+    bool repoDownloadable() const;
+
+    void setSyncNowClicked(bool val) { sync_now_clicked_ = val; }
+    bool syncNowClicked() const { return sync_now_clicked_; }
+
+private:
+    ServerRepo repo_;
+    LocalRepo local_repo_;
+
+    mutable Metrics metrics_;
+    CloneTask clone_task_;
+
+    bool sync_now_clicked_;
+};
+
+/**
+ * Represent a repo category
+ * E.g (My Repos, Shared repos, Group 1 repos, Group 2 repos ...)
+ */
+class RepoCategoryItem: public SeafileRepoBaseItem {
+public:
+    /**
+     * Create a group category
+     * @group_id: -1 for non groups categories
+     *            0 for the groups root item
+     *            > 0 for group items
+     */
+    RepoCategoryItem(int cat_index, const QString& name, int group_id=-1);
+
+    virtual int type() const { return REPO_CATEGORY_TYPE; }
+
+    // Accessors
+    const QString& name() const { return name_; }
+
+    bool isGroupsRoot() const { return group_id_ == 0; }
+
+    bool isGroup() const { return group_id_ > 0; }
+
+    int groupId() const { return group_id_; }
+
+    /**
+     * Although we don't use this in our custom delegate, we need to
+     * implemented it for our proxy filter model.
+     */
+    QVariant data(int role=Qt::UserRole + 1) const;
+
+    int categoryIndex() const { return cat_index_; }
+
+    /**
+     * Return the number of matched repos when the user types filter text
+     */
+    int matchedReposCount() const;
+
+    void resetMatchedRepoCount() { matched_repos_ = 0; };
+    void setMatchedReposCount(int n) { matched_repos_ = n; };
+    void increaseMatchedRepoCount() { matched_repos_++; };
+
+private:
+    int cat_index_;
+    QString name_;
+    int group_id_;
+    int matched_repos_;
+};
+
+#endif // SEAFILE_CLIENT_REPO_ITEM_H
diff --git a/src/ui/repo-tree-model.cpp b/src/ui/repo-tree-model.cpp
new file mode 100644 (file)
index 0000000..ce47cab
--- /dev/null
@@ -0,0 +1,614 @@
+#include <QTimer>
+#include <QHash>
+#include <QDebug>
+#include <algorithm>            // std::sort
+
+#include "api/server-repo.h"
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "main-window.h"
+#include "rpc/rpc-client.h"
+#include "rpc/clone-task.h"
+#include "repo-service.h"
+
+#include "repo-item.h"
+#include "repo-tree-view.h"
+#include "repo-tree-model.h"
+
+namespace {
+
+const int kRefreshLocalReposInterval = 1000;
+const int kMaxRecentUpdatedRepos = 10;
+const int kIndexOfVirtualReposCategory = 2;
+const char *kReadonlyPropertyName = "is-readonly";
+
+bool compareRepoByTimestamp(const ServerRepo& a, const ServerRepo& b)
+{
+    return a.mtime > b.mtime;
+}
+
+QRegExp makeFilterRegExp(const QString& text)
+{
+    return QRegExp(text.split(" ", QString::SkipEmptyParts).join(".*"),
+                   Qt::CaseInsensitive);
+}
+
+
+} // namespace
+
+
+RepoTreeModel::RepoTreeModel(QObject *parent)
+    : QStandardItemModel(parent),
+      tree_view_(NULL)
+{
+    initialize();
+
+    refresh_local_timer_ = new QTimer(this);
+    connect(refresh_local_timer_, SIGNAL(timeout()),
+            this, SLOT(refreshLocalRepos()));
+
+    refresh_local_timer_->start(kRefreshLocalReposInterval);
+}
+
+RepoTreeModel::~RepoTreeModel()
+{
+    if (item(kIndexOfVirtualReposCategory) != virtual_repos_category_)
+        delete virtual_repos_category_;
+}
+
+void RepoTreeModel::initialize()
+{
+    recent_updated_category_ = new RepoCategoryItem(CAT_INDEX_RECENT_UPDATED, tr("Recently Updated"));
+    my_repos_category_ = new RepoCategoryItem(CAT_INDEX_MY_REPOS, tr("My Libraries"));
+    virtual_repos_category_ = new RepoCategoryItem(CAT_INDEX_VIRTUAL_REPOS, tr("Sub Libraries"));
+    shared_repos_category_ = new RepoCategoryItem(CAT_INDEX_SHARED_REPOS, tr("Shared with me"));
+    org_repos_category_ = new RepoCategoryItem(CAT_INDEX_SHARED_REPOS, tr("Shared with all"));
+    groups_root_category_ = new RepoCategoryItem(CAT_INDEX_GROUP_REPOS, tr("Shared with groups"), 0);
+    synced_repos_category_ = new RepoCategoryItem(CAT_INDEX_SYNCED_REPOS, tr("Synced Libraries"));
+
+    appendRow(recent_updated_category_);
+    appendRow(my_repos_category_);
+    // appendRow(virtual_repos_category_);
+    appendRow(shared_repos_category_);
+    appendRow(groups_root_category_);
+    appendRow(synced_repos_category_);
+
+    if (tree_view_) {
+        tree_view_->restoreExpandedCategries();
+    }
+}
+
+QModelIndex RepoTreeModel::proxiedIndexFromItem(const QStandardItem* item)
+{
+    QSortFilterProxyModel *proxy_model = (QSortFilterProxyModel *)tree_view_->model();
+    return proxy_model->mapFromSource(indexFromItem(item));
+}
+
+void RepoTreeModel::clear()
+{
+    beginResetModel();
+    QStandardItemModel::clear();
+    initialize();
+    endResetModel();
+}
+
+void RepoTreeModel::setRepos(const std::vector<ServerRepo>& repos)
+{
+    size_t i, n = repos.size();
+    // removeReposDeletedOnServer(repos);
+
+    clear();
+
+    QHash<QString, ServerRepo> map;
+    const Account& account = seafApplet->accountManager()->currentAccount();
+
+    QHash<QString, QString> merged_repo_perms;
+    // If a repo is shared read-only to org and read-write to me (or vice
+    // versa), the final permission should be read-write.
+    for (i = 0; i < n; i++) {
+        ServerRepo repo = repos[i];
+        QString exist_perm, current_perm;
+
+        if (merged_repo_perms.contains(repo.id)) {
+            exist_perm = merged_repo_perms[repo.id];
+        }
+
+        current_perm = repo.permission;
+        if (repo.owner == account.username && repo.permission == "r") {
+            // When the user shares a repo to organization with read-only
+            // permission, the returned repo has permission set to "r", we need
+            // to fix it.
+            current_perm = "rw";
+        }
+
+        if (current_perm == "rw" || exist_perm == "rw") {
+            merged_repo_perms[repo.id] = "rw";
+        } else {
+            merged_repo_perms[repo.id] = "r";
+        }
+
+        // printf("repo: %s, exist_perm: %s, current_perm: %s, final_perm: %s\n",
+        //        toCStr(repo.name),
+        //        toCStr(exist_perm),
+        //        toCStr(current_perm),
+        //        toCStr(merged_repo_perms[repo.id]));
+    }
+
+    for (i = 0; i < n; i++) {
+        ServerRepo repo = repos[i];
+        repo.permission = merged_repo_perms[repo.id];
+        // TODO: repo.readonly totally depends on repo.permission, so it should
+        // be a function instead of a variable.
+        repo.readonly = repo.permission == "r";
+
+        if (repo.isPersonalRepo()) {
+            if (!repo.isSubfolder() && !repo.isVirtual()) {
+                checkPersonalRepo(repo);
+            }
+        } else if (repo.isSharedRepo()) {
+            checkSharedRepo(repo);
+        } else if (repo.isOrgRepo()) {
+            checkOrgRepo(repo);
+        } else {
+            checkGroupRepo(repo);
+        }
+
+        if (repo.isSubfolder() || seafApplet->rpcClient()->hasLocalRepo(repo.id))
+            checkSyncedRepo(repo);
+
+        // we have a conflicting case, don't use group version if we can
+        if (map.contains(repo.id) && repo.isGroupRepo())
+            continue;
+        map[repo.id] = repo;
+    }
+
+    QList<ServerRepo> list = map.values();
+    // sort all repos by timestamp
+    // use std::sort for qt containers will force additional copy.
+    // anyway, we can use qt's alternative qSort for it
+    std::stable_sort(list.begin(), list.end(), compareRepoByTimestamp);
+
+    n = qMin(list.size(), kMaxRecentUpdatedRepos);
+    for (i = 0; i < n; i++) {
+        RepoItem *item = new RepoItem(list[i]);
+        recent_updated_category_->appendRow(item);
+    }
+    updateLocalReposPerm(list);
+}
+
+void RepoTreeModel::updateLocalReposPerm(const QList<ServerRepo> &repos)
+{
+    int n = repos.size();
+    for (int i = 0; i < n; i++) {
+        ServerRepo repo = repos[i];
+        if (seafApplet->rpcClient()->hasLocalRepo(repo.id)) {
+            QString readonly_prop;
+            if (seafApplet->rpcClient()->getRepoProperty(
+                    repo.id, kReadonlyPropertyName, &readonly_prop) < 0) {
+                continue;
+            }
+            bool readonly = readonly_prop == "true";
+            if (repo.readonly != readonly) {
+                seafApplet->rpcClient()->setRepoProperty(
+                    repo.id,
+                    kReadonlyPropertyName,
+                    repo.readonly ? "true" : "false");
+                qWarning("repo %s %s permission changed to %s",
+                         toCStr(repo.id),
+                         toCStr(repo.name.left(40)),
+                         toCStr(repo.permission));
+            }
+        }
+    }
+}
+
+struct DeleteRepoData {
+    QHash<QString, const ServerRepo*> map;
+    QList<RepoItem*> itemsToDelete;
+};
+
+void RepoTreeModel::collectDeletedRepos(RepoItem *item, void *vdata)
+{
+    DeleteRepoData *data = (DeleteRepoData *)vdata;
+    const ServerRepo* repo = data->map.value(item->repo().id);
+    if (!repo || repo->type != item->repo().type) {
+        data->itemsToDelete << item;
+    }
+}
+
+void RepoTreeModel::removeReposDeletedOnServer(const std::vector<ServerRepo>& repos)
+{
+    int i, n;
+    DeleteRepoData data;
+    n = repos.size();
+    for (i = 0; i < n; i++) {
+        const ServerRepo& repo = repos[i];
+        data.map.insert(repo.id, &repo);
+    }
+
+    forEachRepoItem(&RepoTreeModel::collectDeletedRepos, (void *)&data);
+
+    QListIterator<RepoItem*> iter(data.itemsToDelete);
+    while(iter.hasNext()) {
+        RepoItem *item = iter.next();
+
+        const ServerRepo& repo = item->repo();
+
+        qDebug("remove repo %s(%s) from \"%s\"\n",
+               toCStr(repo.name), toCStr(repo.id),
+               toCStr(((RepoCategoryItem*)item->parent())->name()));
+
+        item->parent()->removeRow(item->row());
+    }
+}
+
+
+void RepoTreeModel::checkPersonalRepo(const ServerRepo& repo)
+{
+    int row, n = my_repos_category_->rowCount();
+    for (row = 0; row < n; row++) {
+        RepoItem *item = (RepoItem *)(my_repos_category_->child(row));
+        if (item->repo().id == repo.id) {
+            updateRepoItem(item, repo);
+            return;
+        }
+    }
+
+    // The repo is new
+    RepoItem *item = new RepoItem(repo);
+    my_repos_category_->appendRow(item);
+}
+
+void RepoTreeModel::checkVirtualRepo(const ServerRepo& repo)
+{
+    if (item(kIndexOfVirtualReposCategory) != virtual_repos_category_) {
+        insertRow(kIndexOfVirtualReposCategory, virtual_repos_category_);
+    }
+
+    int row, n = virtual_repos_category_->rowCount();
+    for (row = 0; row < n; row++) {
+        RepoItem *item = (RepoItem *)(virtual_repos_category_->child(row));
+        if (item->repo().id == repo.id) {
+            updateRepoItem(item, repo);
+            return;
+        }
+    }
+
+    // The repo is new
+    RepoItem *item = new RepoItem(repo);
+    virtual_repos_category_->appendRow(item);
+}
+
+void RepoTreeModel::checkSharedRepo(const ServerRepo& repo)
+{
+    int row, n = shared_repos_category_->rowCount();
+    for (row = 0; row < n; row++) {
+        RepoItem *item = (RepoItem *)(shared_repos_category_->child(row));
+        if (item->repo().id == repo.id) {
+            updateRepoItem(item, repo);
+            return;
+        }
+    }
+
+    // the repo is a new one
+    RepoItem *item = new RepoItem(repo);
+    shared_repos_category_->appendRow(item);
+}
+
+void RepoTreeModel::checkOrgRepo(const ServerRepo& repo)
+{
+    int row, n = org_repos_category_->rowCount();
+    if (invisibleRootItem()->child(3) != org_repos_category_) {
+        // Insert pub repos after "recent updated", "my libraries", "shared libraries"
+        insertRow(3, org_repos_category_);
+    }
+    for (row = 0; row < n; row++) {
+        RepoItem *item = (RepoItem *)(org_repos_category_->child(row));
+        if (item->repo().id == repo.id) {
+            updateRepoItem(item, repo);
+            return;
+        }
+    }
+
+    // the repo is a new one
+    RepoItem *item = new RepoItem(repo);
+    org_repos_category_->appendRow(item);
+}
+
+void RepoTreeModel::checkGroupRepo(const ServerRepo &repo)
+{
+    RepoCategoryItem *group = NULL;
+    int row, n = groups_root_category_->rowCount();
+
+    for (row = 0; row < n; row++) {
+        RepoCategoryItem *item =
+            (RepoCategoryItem *)(groups_root_category_->child(row));
+        if (item->groupId() == repo.group_id) {
+            group = item;
+            break;
+        }
+    }
+
+    if (!group) {
+        group = new RepoCategoryItem(
+            CAT_INDEX_GROUP_REPOS, repo.group_name, repo.group_id);
+        group->setLevel(1);
+        groups_root_category_->appendRow(group);
+    }
+
+    // Find the repo in this group
+    n = group->rowCount();
+    for (row = 0; row < n; row++) {
+        RepoItem *item = (RepoItem *)(group->child(row));
+        if (item->repo().id == repo.id) {
+            item->setLevel(2);
+            updateRepoItem(item, repo);
+            return;
+        }
+    }
+
+    // Current repo not in this group yet
+    RepoItem *item = new RepoItem(repo);
+    item->setLevel(2);
+    group->appendRow(item);
+}
+
+void RepoTreeModel::checkSyncedRepo(const ServerRepo& repo)
+{
+    int row, n = synced_repos_category_->rowCount();
+    for (row = 0; row < n; row++) {
+        RepoItem *item = (RepoItem *)(synced_repos_category_->child(row));
+        if (item->repo().id == repo.id) {
+            updateRepoItem(item, repo);
+            return;
+        }
+    }
+
+    // The repo is new
+    RepoItem *item = new RepoItem(repo);
+    synced_repos_category_->appendRow(item);
+}
+
+void RepoTreeModel::updateRepoItem(RepoItem *item, const ServerRepo& repo)
+{
+    item->setRepo(repo);
+}
+
+void RepoTreeModel::forEachRepoItem(void (RepoTreeModel::*func)(RepoItem *, void *),
+                                    void *data,
+                                    QStandardItem *item)
+{
+    if (item == nullptr) {
+        item = invisibleRootItem();
+    }
+    if (item->type() == REPO_ITEM_TYPE) {
+        (this->*func)((RepoItem *)item, data);
+    }
+
+    int row, n = item->rowCount();
+    for (row = 0; row < n; row++) {
+        forEachRepoItem(func, data, item->child(row));
+    }
+}
+
+void RepoTreeModel::forEachCategoryItem(void (*func)(RepoCategoryItem *, void *),
+                                        void *data,
+                                        QStandardItem *item)
+{
+    if (item == nullptr) {
+        item = invisibleRootItem();
+    }
+    if (item->type() == REPO_CATEGORY_TYPE) {
+        func((RepoCategoryItem *)item, data);
+    }
+
+    int row, n = item->rowCount();
+    for (row = 0; row < n; row++) {
+        forEachCategoryItem(func, data, item->child(row));
+    }
+}
+
+void RepoTreeModel::refreshLocalRepos()
+{
+    if (!seafApplet->mainWindow()->isVisible()) {
+        return;
+    }
+
+    std::vector<CloneTask> tasks;
+    seafApplet->rpcClient()->getCloneTasks(&tasks);
+
+    forEachRepoItem(&RepoTreeModel::refreshRepoItem, (void*) &tasks);
+}
+
+void RepoTreeModel::refreshRepoItem(RepoItem *item, void *data)
+{
+    if (!tree_view_->isExpanded(proxiedIndexFromItem(item->parent()))) {
+        return;
+    }
+
+    if (item->syncNowClicked()) {
+        // Skip refresh repo item on which the user has clicked "sync now"
+        item->setSyncNowClicked(false);
+        return;
+    }
+
+    LocalRepo local_repo;
+    seafApplet->rpcClient()->getLocalRepo(item->repo().id, &local_repo);
+    if (local_repo != item->localRepo()) {
+        // if (local_repo.isValid()) {
+        //     printf("local repo of %s changed\n", local_repo.name.toUtf8().data());
+        // }
+        item->setLocalRepo(local_repo);
+        QModelIndex index = indexFromItem(item);
+        emit dataChanged(index,index);
+        emit repoStatusChanged(index);
+        // printf("repo %s is changed\n", toCStr(item->repo().name));
+    }
+
+    item->setCloneTask();
+
+    CloneTask clone_task;
+    std::vector<CloneTask>* tasks = (std::vector<CloneTask>*)data;
+    if (!local_repo.isValid()) {
+        for (size_t i=0; i < tasks->size(); ++i) {
+            clone_task = tasks->at(i);
+            if (clone_task.repo_id == item->repo().id) {
+                item->setCloneTask(clone_task);
+                QModelIndex index = indexFromItem(item);
+                emit dataChanged(index, index);
+                emit repoStatusChanged(index);
+            }
+        }
+    }
+}
+
+void RepoTreeModel::updateRepoItemAfterSyncNow(const QString& repo_id)
+{
+    QString id = repo_id;
+    forEachRepoItem(&RepoTreeModel::updateRepoItemAfterSyncNow, (void*) &id);
+}
+
+void RepoTreeModel::updateRepoItemAfterSyncNow(RepoItem *item, void *data)
+{
+    QString repo_id = *(QString *)data;
+    LocalRepo r = item->localRepo();
+    if (r.isValid() && r.id == repo_id) {
+        // We manually set the sync state of the repo to "SYNC_STATE_ING" to give
+        // the user immediate feedback
+
+        r.setSyncInfo("initializing");
+        r.sync_state = LocalRepo::SYNC_STATE_ING;
+        r.sync_state_str = tr("sync initializing");
+        item->setLocalRepo(r);
+        item->setSyncNowClicked(true);
+    }
+}
+
+void RepoTreeModel::onFilterTextChanged(const QString& text)
+{
+    // Recalculate the matched repos count for each category
+    QStandardItem *root = invisibleRootItem();
+    int row, n;
+    n = root->rowCount();
+    QRegExp re = makeFilterRegExp(text);
+    for (row = 0; row < n; row++) {
+        RepoCategoryItem *category = (RepoCategoryItem *)root->child(row);
+        if (category->isGroupsRoot()) {
+            continue;
+        }
+        int j, total, matched = 0;
+        total = category->rowCount();
+        for (j = 0; j < total; j++) {
+            RepoItem *item = (RepoItem *)category->child(j);
+            if (item->repo().name.contains(re)) {
+                matched++;
+            }
+        }
+        category->setMatchedReposCount(matched);
+    }
+}
+
+RepoFilterProxyModel::RepoFilterProxyModel(QObject *parent)
+    : QSortFilterProxyModel(parent),
+      has_filter_(false)
+{
+}
+
+void RepoFilterProxyModel::setSourceModel(QAbstractItemModel *source_model)
+{
+    QSortFilterProxyModel::setSourceModel(source_model);
+    RepoTreeModel *tree_model = (RepoTreeModel *)source_model;
+    connect(tree_model, SIGNAL(repoStatusChanged(const QModelIndex&)),
+            this, SLOT(onRepoStatusChanged(const QModelIndex&)));
+}
+
+void RepoFilterProxyModel::onRepoStatusChanged(const QModelIndex& source_index)
+{
+    QModelIndex index = mapFromSource(source_index);
+    emit dataChanged(index, index);
+}
+
+bool RepoFilterProxyModel::filterAcceptsRow(int source_row,
+                        const QModelIndex & source_parent) const
+{
+    RepoTreeModel *tree_model = (RepoTreeModel *)(sourceModel());
+    QModelIndex index = tree_model->index(source_row, 0, source_parent);
+    QStandardItem *item = tree_model->itemFromIndex(index);
+    if (item->type() == REPO_CATEGORY_TYPE) {
+        // RepoCategoryItem *category = (RepoCategoryItem *)item;
+        // We don't filter repo categories, only filter repos by name.
+        return true;
+    } else if (item->type() == REPO_ITEM_TYPE) {
+        // Use default filtering (filter by item DisplayRole, i.e. repo name)
+        bool match = QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
+        // if (match) {
+        //     RepoCategoryItem *category = (RepoCategoryItem *)(item->parent());
+        // }
+        return match;
+    }
+
+    return false;
+}
+
+void RepoFilterProxyModel::setFilterText(const QString& text)
+{
+    has_filter_ = !text.isEmpty();
+    invalidate();
+    setFilterRegExp(makeFilterRegExp(text));
+}
+
+// void RepoFilterProxyModel::sort()
+// {
+// }
+
+bool RepoFilterProxyModel::lessThan(const QModelIndex &left,
+                                    const QModelIndex &right) const
+{
+    RepoTreeModel *tree_model = (RepoTreeModel *)(sourceModel());
+    QStandardItem *item_l = tree_model->itemFromIndex(left);
+    QStandardItem *item_r = tree_model->itemFromIndex(right);
+
+    /**
+     * When we have filter: sort category by matched repos count
+     * When we have no filter: sort category by category index order
+     *
+     */
+    if (item_l->type() == REPO_CATEGORY_TYPE) {
+        // repo categories
+        RepoCategoryItem *cl = (RepoCategoryItem *)item_l;
+        RepoCategoryItem *cr = (RepoCategoryItem *)item_r;
+        if (has_filter_) {
+            // printf ("%s matched: %d, %s matched: %d\n",
+            //         cl->name().toUtf8().data(), cl->matchedReposCount(),
+            //         cr->name().toUtf8().data(), cr->matchedReposCount());
+            return cl->matchedReposCount() > cr->matchedReposCount();
+        } else {
+            int cat_l = cl->categoryIndex();
+            int cat_r = cr->categoryIndex();
+            if (cat_l == cat_r) {
+                return cl->name() < cr->name();
+            } else {
+                return cat_l < cat_r;
+            }
+        }
+    } else {
+        // repos
+        RepoItem *cl = (RepoItem *)item_l;
+        RepoItem *cr = (RepoItem *)item_r;
+        if (cl->repo().mtime != cr->repo().mtime) {
+            return cl->repo().mtime > cr->repo().mtime;
+        } else {
+            return cl->repo().name > cr->repo().name;
+        }
+    }
+
+    return false;
+}
+
+Qt::ItemFlags RepoFilterProxyModel::flags(const QModelIndex& index) const
+{
+    Qt::ItemFlags flgs =  QSortFilterProxyModel::flags(index);
+    return flgs & ~Qt::ItemIsEditable;
+}
diff --git a/src/ui/repo-tree-model.h b/src/ui/repo-tree-model.h
new file mode 100644 (file)
index 0000000..3f4d66d
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef SEAFILE_CLIENT_REPO_TREE_MODEL_H
+#define SEAFILE_CLIENT_REPO_TREE_MODEL_H
+
+#include <vector>
+#include <QStandardItemModel>
+#include <QSortFilterProxyModel>
+#include <QModelIndex>
+
+class ServerRepo;
+class RepoItem;
+class RepoCategoryItem;
+class QTimer;
+class RepoTreeView;
+
+/**
+ * Tree model for repos. There are two levels of items:
+ *
+ * The first level: (RepoCategory)
+ *  - My Libraries
+ *  - Shared Libraries
+ *  - Group 1
+ *  - Group 2
+ *  - Group N
+ *
+ * The sencond level is the libraries belonging to the first level item (RepoItem)
+ *
+ *  - My Libraries
+ *    - Notes
+ *    - Musics
+ *    - Logs
+ */
+class RepoTreeModel : public QStandardItemModel {
+    Q_OBJECT
+
+public:
+    /**
+     * The default sorting order of repo categroies.
+     */
+    enum RepoCategoryIndex {
+        CAT_INDEX_RECENT_UPDATED = 0,
+        CAT_INDEX_MY_REPOS,
+        CAT_INDEX_VIRTUAL_REPOS,
+        CAT_INDEX_SHARED_REPOS,
+        CAT_INDEX_PUBLIC_REPOS,
+        CAT_INDEX_GROUP_REPOS,
+        CAT_INDEX_SYNCED_REPOS,
+    };
+
+    RepoTreeModel(QObject *parent=0);
+    ~RepoTreeModel();
+    void setRepos(const std::vector<ServerRepo>& repos);
+
+    void clear();
+
+    void setTreeView(RepoTreeView *view) { tree_view_ = view; }
+    RepoTreeView* treeView() { return tree_view_; }
+
+    void updateRepoItemAfterSyncNow(const QString& repo_id);
+    void onFilterTextChanged(const QString& text);
+    int repo_category_height;
+
+signals:
+    void repoStatusChanged(const QModelIndex& index);
+
+private slots:
+    void refreshLocalRepos();
+
+private:
+    void checkPersonalRepo(const ServerRepo& repo);
+    void checkVirtualRepo(const ServerRepo& repo);
+    void checkSharedRepo(const ServerRepo& repo);
+    void checkOrgRepo(const ServerRepo& repo);
+    void checkGroupRepo(const ServerRepo& repo);
+    void checkSyncedRepo(const ServerRepo& repo);
+    void initialize();
+    void updateLocalReposPerm(const QList<ServerRepo>& repos);
+    void updateRepoItem(RepoItem *item, const ServerRepo& repo);
+    void refreshRepoItem(RepoItem *item, void *data);
+
+    void forEachRepoItem(void (RepoTreeModel::*func)(RepoItem *, void *),
+                         void *data,
+                         QStandardItem *root = nullptr);
+
+    void forEachCategoryItem(void (*func)(RepoCategoryItem*, void *),
+                             void *data,
+                             QStandardItem *root = nullptr);
+
+    void removeReposDeletedOnServer(const std::vector<ServerRepo> &repos);
+
+    void collectDeletedRepos(RepoItem *item, void *vdata);
+    void updateRepoItemAfterSyncNow(RepoItem *item, void *data);
+    QModelIndex proxiedIndexFromItem(const QStandardItem* item);
+
+    RepoCategoryItem *recent_updated_category_;
+    RepoCategoryItem *my_repos_category_;
+    RepoCategoryItem *virtual_repos_category_;
+    RepoCategoryItem *shared_repos_category_;
+    RepoCategoryItem *org_repos_category_;
+    RepoCategoryItem *groups_root_category_;
+    RepoCategoryItem *synced_repos_category_;
+
+    QTimer *refresh_local_timer_;
+
+    RepoTreeView *tree_view_;
+};
+
+/**
+ * This model is used to implement (only show repos filtered by user typed text)
+ */
+class RepoFilterProxyModel : public QSortFilterProxyModel {
+    Q_OBJECT
+public:
+    RepoFilterProxyModel(QObject* parent=0);
+
+    void setSourceModel(QAbstractItemModel *source_model);
+
+    void setFilterText(const QString& text);
+    bool filterAcceptsRow(int source_row,
+                          const QModelIndex & source_parent) const;
+    bool lessThan(const QModelIndex &left,
+                  const QModelIndex &right) const;
+    Qt::ItemFlags flags(const QModelIndex& index) const;
+
+private slots:
+    void onRepoStatusChanged(const QModelIndex& source_index);
+
+private:
+    bool has_filter_;
+};
+
+#endif // SEAFILE_CLIENT_REPO_TREE_MODEL_H
diff --git a/src/ui/repo-tree-view.cpp b/src/ui/repo-tree-view.cpp
new file mode 100644 (file)
index 0000000..47d095b
--- /dev/null
@@ -0,0 +1,1110 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QHeaderView>
+#include <QDesktopServices>
+#include <QEvent>
+#include <QShowEvent>
+#include <QHideEvent>
+#include <QInputDialog>
+#include <Qt>
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "settings-mgr.h"
+#include "account-mgr.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "download-repo-dialog.h"
+#include "clone-tasks-dialog.h"
+#include "repo-item.h"
+#include "repo-item-delegate.h"
+#include "repo-tree-model.h"
+#include "repo-detail-dialog.h"
+#include "utils/paint-utils.h"
+#include "repo-service.h"
+#include "auto-login-service.h"
+
+#include "filebrowser/file-browser-manager.h"
+#include "filebrowser/file-browser-dialog.h"
+#include "utils/utils-mac.h"
+#include "filebrowser/tasks.h"
+#include "filebrowser/progress-dialog.h"
+#include "ui/set-repo-password-dialog.h"
+#include "ui/private-share-dialog.h"
+#include "ui/check-repo-root-perm-dialog.h"
+
+#include "repo-tree-view.h"
+
+namespace {
+
+const char *kRepoTreeViewSettingsGroup = "RepoTreeView";
+const char *kRepoTreeViewSettingsExpandedCategories = "expandedCategories";
+const char *kSyncIntervalProperty = "sync-interval";
+
+// A Helper Class to copy file
+//
+class FileCopyHelper : public QRunnable {
+public:
+    FileCopyHelper(const QString &source, const QString &target,
+                   RepoTreeView *parent)
+    : source_(source),
+      target_(target),
+      parent_(parent) {
+    }
+signals:
+    void success(bool);
+private:
+    void run() {
+        if (!QFile::copy(source_, target_)) {
+            // cannot do GUI operations in this thread
+            // callback to the main thread
+            QMetaObject::invokeMethod(parent_, "copyFileFailed");
+        }
+    }
+    bool autoDelete() {
+        return true;
+    }
+    const QString source_;
+    const QString target_;
+    RepoTreeView *parent_;
+};
+
+FileCopyHelper* copyFile(const QString &source, const QString &target, RepoTreeView *parent) {
+      FileCopyHelper* helper = new FileCopyHelper(source, target, parent);
+      QThreadPool *pool = QThreadPool::globalInstance();
+      pool->start(helper);
+      return helper;
+}
+
+} // anonymous namespace
+
+static ServerRepo selected_repo_;
+// TODO save localrepo as well to avoid many copys
+
+RepoTreeView::RepoTreeView(QWidget *parent)
+    : QTreeView(parent)
+{
+    header()->hide();
+    createActions();
+
+    // We draw the indicator ourselves
+    setIndentation(0);
+    // We handle the click oursevles
+    setExpandsOnDoubleClick(false);
+
+    connect(this, SIGNAL(clicked(const QModelIndex&)),
+            this, SLOT(onItemClicked(const QModelIndex&)));
+
+    connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+            this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+#if defined(Q_OS_MAC)
+    this->setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+
+    loadExpandedCategries();
+    connect(qApp, SIGNAL(aboutToQuit()),
+            this, SLOT(saveExpandedCategries()));
+    connect(seafApplet->accountManager(), SIGNAL(beforeAccountSwitched()),
+            this, SLOT(saveExpandedCategries()));
+    connect(seafApplet->accountManager(), SIGNAL(accountsChanged()),
+            this, SLOT(loadExpandedCategries()));
+    connect(seafApplet->settingsManager(), SIGNAL(autoSyncChanged(bool)),
+            this, SLOT(update()));
+
+    setAcceptDrops(true);
+    setDefaultDropAction(Qt::CopyAction);
+    // setAlternatingRowColors(true);
+    setDropIndicatorShown(true);
+
+    current_drop_target_ = QModelIndex();
+    previous_drop_target_ = QModelIndex();
+}
+
+void RepoTreeView::loadExpandedCategries()
+{
+    Account account = seafApplet->accountManager()->currentAccount();
+    if (!account.isValid()) {
+        return;
+    }
+    expanded_categroies_.clear();
+    QSettings settings;
+    settings.beginGroup(kRepoTreeViewSettingsGroup);
+    QString key = QString(kRepoTreeViewSettingsExpandedCategories) + "-" + account.getSignature();
+    if (settings.contains(key)) {
+        QString cats = settings.value(key, "").toString();
+        expanded_categroies_ = QSet<QString>::fromList(cats.split("\t", QString::SkipEmptyParts));
+    } else {
+        // Expand "recent updated" on first use
+        expanded_categroies_.insert(tr("Recently Updated"));
+    }
+    settings.endGroup();
+}
+
+void RepoTreeView::contextMenuEvent(QContextMenuEvent *event)
+{
+    QPoint pos = event->pos();
+    QModelIndex index = indexAt(pos);
+    if (!index.isValid()) {
+        // Not clicked at a repo item
+        return;
+    }
+
+    QStandardItem *item = getRepoItem(index);
+    if (!item || item->type() != REPO_ITEM_TYPE) {
+        return;
+    }
+    updateRepoActions();
+    QMenu *menu = prepareContextMenu((RepoItem *)item);
+    pos = viewport()->mapToGlobal(pos);
+    menu->exec(pos);
+    menu->deleteLater();
+}
+
+QMenu* RepoTreeView::prepareContextMenu(const RepoItem *item)
+{
+    QMenu *menu = new QMenu(this);
+    if (item->localRepo().isValid()) {
+        menu->addAction(open_local_folder_action_);
+    }
+
+    if (item->repoDownloadable()) {
+        menu->addAction(download_action_);
+    }
+
+    menu->addAction(view_on_web_action_);
+    menu->addAction(open_in_filebrowser_action_);
+
+    if (item->repo().isSharedRepo()) {
+        menu->addAction(unshare_action_);
+    }
+
+    const Account& account = seafApplet->accountManager()->currentAccount();
+    if (account.isPro() && account.username == item->repo().owner) {
+        menu->addSeparator();
+        menu->addAction(share_repo_to_user_action_);
+        menu->addAction(share_repo_to_group_action_);
+        menu->addSeparator();
+    }
+
+    if (item->localRepo().isValid()) {
+        menu->addSeparator();
+        menu->addAction(toggle_auto_sync_action_);
+        menu->addAction(sync_now_action_);
+        menu->addAction(set_sync_interval_action_);
+        menu->addSeparator();
+    }
+
+    menu->addAction(show_detail_action_);
+
+    if (item->cloneTask().isCancelable()) {
+        menu->addAction(cancel_download_action_);
+    }
+    if (item->localRepo().isValid()) {
+        menu->addAction(unsync_action_);
+        menu->addAction(resync_action_);
+    }
+
+    return menu;
+}
+
+void RepoTreeView::updateRepoActions()
+{
+    RepoItem *item = NULL;
+    QItemSelection selected = selectionModel()->selection();
+    QModelIndexList indexes = selected.indexes();
+    if (indexes.size() != 0) {
+        const QModelIndex& index = indexes.at(0);
+        QSortFilterProxyModel *proxy = (QSortFilterProxyModel *)model();
+        RepoTreeModel *tree_model = (RepoTreeModel *)(proxy->sourceModel());
+        QStandardItem *it = tree_model->itemFromIndex(proxy->mapToSource(index));
+        if (it && it->type() == REPO_ITEM_TYPE) {
+            item = (RepoItem *)it;
+        }
+    }
+
+    if (!item) {
+        // No repo item is selected
+        download_action_->setEnabled(false);
+        download_toolbar_action_->setEnabled(false);
+        sync_now_action_->setEnabled(false);
+        open_local_folder_action_->setEnabled(false);
+        open_local_folder_toolbar_action_->setEnabled(false);
+        unsync_action_->setEnabled(false);
+        resync_action_->setEnabled(false);
+        set_sync_interval_action_->setEnabled(false);
+        toggle_auto_sync_action_->setEnabled(false);
+        view_on_web_action_->setEnabled(false);
+        open_in_filebrowser_action_->setEnabled(false);
+        show_detail_action_->setEnabled(false);
+        return;
+    }
+
+    LocalRepo r;
+    seafApplet->rpcClient()->getLocalRepo(item->repo().id, &r);
+    item->setLocalRepo(r);
+
+    if (item->localRepo().isValid()) {
+        const LocalRepo& local_repo = item->localRepo();
+        download_action_->setEnabled(false);
+        download_toolbar_action_->setEnabled(false);
+
+        sync_now_action_->setEnabled(true);
+        sync_now_action_->setData(QVariant::fromValue(local_repo));
+
+        open_local_folder_action_->setData(QVariant::fromValue(local_repo));
+        open_local_folder_action_->setEnabled(true);
+        open_local_folder_toolbar_action_->setData(QVariant::fromValue(local_repo));
+        open_local_folder_toolbar_action_->setEnabled(true);
+
+        unsync_action_->setData(QVariant::fromValue(local_repo));
+        unsync_action_->setEnabled(true);
+
+        resync_action_->setData(QVariant::fromValue(local_repo));
+        resync_action_->setEnabled(true);
+
+        set_sync_interval_action_->setData(QVariant::fromValue(local_repo));
+        set_sync_interval_action_->setEnabled(true);
+
+        if (seafApplet->settingsManager()->autoSync()) {
+            toggle_auto_sync_action_->setData(QVariant::fromValue(local_repo));
+            toggle_auto_sync_action_->setEnabled(true);
+        } else {
+            toggle_auto_sync_action_->setEnabled(false);
+        }
+
+        if (local_repo.auto_sync) {
+            toggle_auto_sync_action_->setText(tr("Disable auto sync"));
+            toggle_auto_sync_action_->setToolTip(tr("Disable auto sync"));
+            toggle_auto_sync_action_->setIcon(QIcon(":/images/pause-gray.png"));
+        } else {
+            toggle_auto_sync_action_->setText(tr("Enable auto sync"));
+            toggle_auto_sync_action_->setToolTip(tr("Enable auto sync"));
+            toggle_auto_sync_action_->setIcon(QIcon(":/images/play-gray.png"));
+        }
+
+    } else {
+        if (item->repoDownloadable()) {
+            download_action_->setEnabled(true);
+            download_toolbar_action_->setEnabled(true);
+        } else {
+            download_action_->setEnabled(false);
+            download_toolbar_action_->setEnabled(false);
+        }
+
+        sync_now_action_->setEnabled(false);
+
+        open_local_folder_action_->setEnabled(false);
+        open_local_folder_toolbar_action_->setEnabled(false);
+        unsync_action_->setEnabled(false);
+        resync_action_->setEnabled(false);
+        set_sync_interval_action_->setEnabled(false);
+        toggle_auto_sync_action_->setEnabled(false);
+    }
+
+    selected_repo_ = item->repo();
+    view_on_web_action_->setEnabled(true);
+    open_in_filebrowser_action_->setEnabled(true);
+
+    show_detail_action_->setEnabled(true);
+
+    if (item->cloneTask().isCancelable()) {
+        cancel_download_action_->setEnabled(true);
+    } else {
+        cancel_download_action_->setEnabled(false);
+    }
+    emit dataChanged(indexes.at(0), indexes.at(0));
+}
+
+QStandardItem* RepoTreeView::getRepoItem(const QModelIndex &index) const
+{
+    if (!index.isValid()) {
+        return NULL;
+    }
+    QSortFilterProxyModel *proxy = (QSortFilterProxyModel *)model();
+    RepoTreeModel *tree_model = (RepoTreeModel *)(proxy->sourceModel());
+    const QModelIndex mapped_index = proxy->mapToSource(index);
+    QStandardItem *item = tree_model->itemFromIndex(mapped_index);
+
+    if (item->type() != REPO_ITEM_TYPE &&
+        item->type() != REPO_CATEGORY_TYPE) {
+        return NULL;
+    }
+    return item;
+}
+
+void RepoTreeView::createActions()
+{
+    show_detail_action_ = new QAction(tr("Show &details"), this);
+    show_detail_action_->setIcon(QIcon(":/images/info-gray.png"));
+    show_detail_action_->setStatusTip(tr("Show details of this library"));
+    show_detail_action_->setIconVisibleInMenu(true);
+    connect(show_detail_action_, SIGNAL(triggered()), this, SLOT(showRepoDetail()));
+
+    download_action_ = new QAction(tr("&Sync this library"), this);
+    download_action_->setIcon(QIcon(":/images/toolbar/download-gray.png"));
+    download_action_->setStatusTip(tr("Sync this library"));
+    download_action_->setIconVisibleInMenu(true);
+    connect(download_action_, SIGNAL(triggered()), this, SLOT(downloadRepo()));
+
+    download_toolbar_action_ = new QAction(tr("&Sync this library"), this);
+    download_toolbar_action_->setIcon(QIcon(":/images/toolbar/download.png"));
+    download_toolbar_action_->setStatusTip(tr("Sync this library"));
+    download_toolbar_action_->setIconVisibleInMenu(false);
+    connect(download_toolbar_action_, SIGNAL(triggered()), this, SLOT(downloadRepo()));
+
+    sync_now_action_ = new QAction(tr("Sync &now"), this);
+    sync_now_action_->setIcon(QIcon(":/images/sync_now-gray.png"));
+    sync_now_action_->setStatusTip(tr("Sync this library immediately"));
+    sync_now_action_->setIconVisibleInMenu(true);
+    connect(sync_now_action_, SIGNAL(triggered()), this, SLOT(syncRepoImmediately()));
+    cancel_download_action_ = new QAction(tr("&Cancel download"), this);
+    cancel_download_action_->setIcon(QIcon(":/images/remove-gray.png"));
+    cancel_download_action_->setStatusTip(tr("Cancel download of this library"));
+    cancel_download_action_->setIconVisibleInMenu(true);
+    connect(cancel_download_action_, SIGNAL(triggered()), this, SLOT(cancelDownload()));
+
+    open_local_folder_action_ = new QAction(tr("&Open local folder"), this);
+    open_local_folder_action_->setIcon(QIcon(":/images/toolbar/file-gray.png"));
+    open_local_folder_action_->setStatusTip(tr("open local folder"));
+    open_local_folder_action_->setIconVisibleInMenu(true);
+    connect(open_local_folder_action_, SIGNAL(triggered()), this, SLOT(openLocalFolder()));
+
+    open_local_folder_toolbar_action_ = new QAction(tr("&Open folder"), this);
+    open_local_folder_toolbar_action_->setIcon(QIcon(":/images/toolbar/file.png"));
+    open_local_folder_toolbar_action_->setStatusTip(tr("open local folder"));
+    open_local_folder_toolbar_action_->setIconVisibleInMenu(true);
+    connect(open_local_folder_toolbar_action_, SIGNAL(triggered()), this, SLOT(openLocalFolder()));
+
+    unsync_action_ = new QAction(tr("&Unsync"), this);
+    unsync_action_->setStatusTip(tr("unsync this library"));
+    unsync_action_->setIcon(QIcon(":/images/minus-gray.png"));
+    unsync_action_->setIconVisibleInMenu(true);
+    connect(unsync_action_, SIGNAL(triggered()), this, SLOT(unsyncRepo()));
+
+    toggle_auto_sync_action_ = new QAction(tr("Enable auto sync"), this);
+    toggle_auto_sync_action_->setStatusTip(tr("Enable auto sync"));
+    toggle_auto_sync_action_->setIconVisibleInMenu(true);
+    connect(toggle_auto_sync_action_, SIGNAL(triggered()), this, SLOT(toggleRepoAutoSync()));
+
+    view_on_web_action_ = new QAction(tr("&View on cloud"), this);
+    view_on_web_action_->setIcon(QIcon(":/images/cloud-gray.png"));
+    view_on_web_action_->setStatusTip(tr("view this library on seahub"));
+    view_on_web_action_->setIconVisibleInMenu(true);
+
+    connect(view_on_web_action_, SIGNAL(triggered()), this, SLOT(viewRepoOnWeb()));
+
+    share_repo_to_user_action_ = new QAction(tr("Share to user"), this);
+    share_repo_to_user_action_->setIcon(QIcon(":/images/share.png"));
+    share_repo_to_user_action_->setStatusTip(tr("Share this library to a user"));
+    share_repo_to_user_action_->setIconVisibleInMenu(true);
+
+    connect(share_repo_to_user_action_, SIGNAL(triggered()), this, SLOT(shareRepoToUser()));
+
+    share_repo_to_group_action_ = new QAction(tr("Share to group"), this);
+    share_repo_to_group_action_->setIcon(QIcon(":/images/share.png"));
+    share_repo_to_group_action_->setStatusTip(tr("Share this library to a group"));
+    share_repo_to_group_action_->setIconVisibleInMenu(true);
+
+    connect(share_repo_to_group_action_, SIGNAL(triggered()), this, SLOT(shareRepoToGroup()));
+
+    QString open_action_text = tr("&Open cloud file browser");
+    if (open_action_text.contains("%")) {
+        // In German translation there is a "seafile" string, so need to use tr("..").arg(..) here
+        open_action_text = open_action_text.arg(getBrand());
+    }
+
+    open_in_filebrowser_action_ = new QAction(open_action_text, this);
+    open_in_filebrowser_action_->setIcon(QIcon(":/images/cloud-gray.png"));
+    open_in_filebrowser_action_->setStatusTip(tr("open this library in embedded Cloud File Browser"));
+    open_in_filebrowser_action_->setIconVisibleInMenu(true);
+
+    connect(open_in_filebrowser_action_, SIGNAL(triggered()), this, SLOT(openInFileBrowser()));
+
+    unshare_action_ = new QAction(tr("&Leave share"), this);
+    unshare_action_->setIcon(QIcon(":/images/leave-share.png"));
+    unshare_action_->setStatusTip(tr("leave share"));
+
+    connect(unshare_action_, SIGNAL(triggered()), this, SLOT(unshareRepo()));
+
+    resync_action_ = new QAction(tr("&Resync this library"), this);
+    resync_action_->setIcon(QIcon(":/images/resync.png"));
+    resync_action_->setStatusTip(tr("unsync and resync this library"));
+
+    connect(resync_action_, SIGNAL(triggered()), this, SLOT(resyncRepo()));
+
+    set_sync_interval_action_ = new QAction(tr("Set sync &Interval"), this);
+    set_sync_interval_action_->setIcon(QIcon(":/images/clock.png"));
+    set_sync_interval_action_->setStatusTip(tr("set sync interval for this library"));
+
+    connect(set_sync_interval_action_, SIGNAL(triggered()), this, SLOT(setRepoSyncInterval()));
+}
+
+void RepoTreeView::downloadRepo()
+{
+    DownloadRepoDialog dialog(seafApplet->accountManager()->currentAccount(), selected_repo_, QString(), this);
+
+    dialog.exec();
+
+    updateRepoActions();
+}
+
+void RepoTreeView::showRepoDetail()
+{
+    RepoDetailDialog dialog(selected_repo_, this);
+    dialog.exec();
+}
+
+void RepoTreeView::openLocalFolder()
+{
+    LocalRepo repo = qvariant_cast<LocalRepo>(open_local_folder_action_->data());
+    QDesktopServices::openUrl(QUrl::fromLocalFile(repo.worktree));
+}
+
+void RepoTreeView::toggleRepoAutoSync()
+{
+    LocalRepo repo = qvariant_cast<LocalRepo>(toggle_auto_sync_action_->data());
+
+    seafApplet->rpcClient()->setRepoAutoSync(repo.id, !repo.auto_sync);
+
+    updateRepoActions();
+}
+
+void RepoTreeView::unsyncRepo()
+{
+    LocalRepo repo = qvariant_cast<LocalRepo>(toggle_auto_sync_action_->data());
+
+    QString question = tr("Are you sure to unsync the library \"%1\"?").arg(repo.name);
+
+    if (!seafApplet->yesOrCancelBox(question, this, false)) {
+        return;
+    }
+
+    unsyncRepoImpl(repo);
+}
+
+void RepoTreeView::unsyncRepoImpl(const LocalRepo& repo)
+{
+    if (seafApplet->rpcClient()->unsync(repo.id) < 0) {
+        seafApplet->warningBox(tr("Failed to unsync library \"%1\"").arg(repo.name), this);
+    }
+    ServerRepo server_repo = RepoService::instance()->getRepo(repo.id);
+    if (server_repo.isValid() && server_repo.isSubfolder())
+        RepoService::instance()->removeSyncedSubfolder(repo.id);
+
+    updateRepoActions();
+}
+
+void RepoTreeView::onItemClicked(const QModelIndex& index)
+{
+    QStandardItem *item = getRepoItem(index);
+    if (!item) {
+        return;
+    }
+    if (item->type() == REPO_ITEM_TYPE) {
+        return;
+    } else {
+        // A repo category item
+        if (isExpanded(index)) {
+            collapse(index);
+        } else {
+            expand(index);
+        }
+    }
+}
+
+void RepoTreeView::onItemDoubleClicked(const QModelIndex& index)
+{
+    QStandardItem *item = getRepoItem(index);
+    if (!item) {
+        return;
+    }
+    if (item->type() == REPO_ITEM_TYPE) {
+        RepoItem *it = (RepoItem *)item;
+        const LocalRepo& local_repo = it->localRepo();
+        if (local_repo.isValid()) {
+            // open local folder for downloaded repo
+            QDesktopServices::openUrl(QUrl::fromLocalFile(local_repo.worktree));
+        } else {
+            // open seahub repo page for not downloaded repo
+            FileBrowserManager::getInstance()->openOrActivateDialog(
+                seafApplet->accountManager()->currentAccount(),
+                it->repo());
+        }
+    }
+}
+
+void RepoTreeView::viewRepoOnWeb()
+{
+    const Account account = seafApplet->accountManager()->currentAccount();
+    if (account.isValid()) {
+        // we adopt a new format of cloud view url from server version 4.2.0
+        if (!account.isAtLeastVersion(4, 2, 0)) {
+            QDesktopServices::openUrl(account.getAbsoluteUrl("repo/" + selected_repo_.id));
+        } else {
+            AutoLoginService::instance()->startAutoLogin("/#common/lib/" + selected_repo_.id + "/");
+        }
+    }
+}
+
+void RepoTreeView::shareRepo(bool to_group)
+{
+    const Account account = seafApplet->accountManager()->currentAccount();
+    PrivateShareDialog dialog(account, selected_repo_.id, selected_repo_.name,
+                              "/", to_group,
+                              this);
+    dialog.exec();
+}
+
+void RepoTreeView::shareRepoToUser()
+{
+    shareRepo(false);
+}
+
+void RepoTreeView::shareRepoToGroup()
+{
+    shareRepo(true);
+}
+
+void RepoTreeView::unshareRepo()
+{
+    if (!seafApplet->yesOrNoBox(
+            tr("Are you sure you want to leave the share \"%1\"?").arg(
+                selected_repo_.name), this, false)) {
+        return;
+    }
+
+    const Account account = seafApplet->accountManager()->currentAccount();
+    const QString repo_id = selected_repo_.id;
+    const QString from_user = selected_repo_.owner;
+    UnshareRepoRequest* request =
+        new UnshareRepoRequest(account, repo_id, from_user);
+
+    connect(request, SIGNAL(success()),
+            this, SLOT(onUnshareSuccess()));
+    connect(request, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onUnshareFailed(const ApiError&)));
+
+    request->send();
+}
+
+void RepoTreeView::onUnshareSuccess()
+{
+    RepoService::instance()->refresh(true);
+
+    UnshareRepoRequest* req = qobject_cast<UnshareRepoRequest*>(sender());
+    if (!req) {
+        return;
+    } else {
+        req->deleteLater();
+    }
+
+    LocalRepo local_repo;
+    seafApplet->rpcClient()->getLocalRepo(req->repoId(), &local_repo);
+    if (local_repo.isValid()) {
+        unsyncRepoImpl(local_repo);
+    }
+}
+
+void RepoTreeView::onUnshareFailed(const ApiError&error)
+{
+    seafApplet->warningBox(tr("Leaving share failed"), this);
+}
+
+void RepoTreeView::openInFileBrowser()
+{
+    const Account account = seafApplet->accountManager()->currentAccount();
+    if (account.isValid()) {
+        FileBrowserManager::getInstance()->openOrActivateDialog(
+            seafApplet->accountManager()->currentAccount(),
+            selected_repo_);
+    }
+}
+
+bool RepoTreeView::viewportEvent(QEvent *event)
+{
+    if (event->type() != QEvent::ToolTip &&
+        event->type() != QEvent::WhatsThis &&
+        event->type() != QEvent::MouseButtonPress &&
+        event->type() != QEvent::MouseButtonRelease)
+    {
+        return QTreeView::viewportEvent(event);
+    }
+
+    QPoint global_pos = QCursor::pos();
+    QPoint viewport_pos = viewport()->mapFromGlobal(global_pos);
+    QModelIndex index = indexAt(viewport_pos);
+    if (!index.isValid()) {
+        return true;
+    }
+
+    QStandardItem *item = getRepoItem(index);
+    if (!item) {
+        return true;
+    }
+
+    // handle the event in the top
+    const QModelIndex top_index = indexAt(QPoint(0, 0));
+    if (event->type() == QEvent::MouseButtonPress ||
+        event->type() == QEvent::MouseButtonRelease)
+    {
+        QSortFilterProxyModel *proxy = (QSortFilterProxyModel *)model();
+        RepoTreeModel *tree_model = (RepoTreeModel *)(proxy->sourceModel());
+
+        if (index == top_index &&
+            top_index.parent().isValid() &&
+            viewport_pos.y() <= tree_model->repo_category_height)
+        {
+            QMouseEvent *ev = static_cast<QMouseEvent*>(event);
+            if (!(ev->buttons() & Qt::LeftButton)) {
+                return true;
+            } else {
+                const QModelIndex parent = top_index.parent();
+                setExpanded(parent, !isExpanded(parent));
+                return true;
+            }
+        }
+        return QTreeView::viewportEvent(event);
+    }
+
+    QRect item_rect = visualRect(index);
+    if (item->type() == REPO_ITEM_TYPE) {
+        showRepoItemToolTip((RepoItem *)item, global_pos, item_rect);
+    } else {
+        showRepoCategoryItemToolTip((RepoCategoryItem *)item, global_pos, item_rect);
+    }
+
+    return true;
+}
+
+void RepoTreeView::showRepoItemToolTip(const RepoItem *item,
+                                       const QPoint& pos,
+                                       const QRect& rect)
+{
+    RepoItemDelegate *delegate = (RepoItemDelegate *)itemDelegate();
+    delegate->showRepoItemToolTip(item, pos, viewport(), rect);
+}
+
+void RepoTreeView::showRepoCategoryItemToolTip(const RepoCategoryItem *item,
+                                               const QPoint& pos,
+                                               const QRect& rect)
+{
+    QToolTip::showText(pos, item->name(), viewport(), rect);
+    // QToolTip::showText(pos, item->name());
+}
+
+std::vector<QAction*> RepoTreeView::getToolBarActions()
+{
+    std::vector<QAction*> actions;
+
+    updateRepoActions();
+
+    actions.push_back(download_toolbar_action_);
+    actions.push_back(open_local_folder_toolbar_action_);
+    return actions;
+}
+
+void RepoTreeView::selectionChanged(const QItemSelection &selected,
+                                    const QItemSelection &deselected)
+{
+    updateRepoActions();
+}
+
+void RepoTreeView::hideEvent(QHideEvent *event)
+{
+    download_action_->setEnabled(false);
+    download_toolbar_action_->setEnabled(false);
+    open_local_folder_action_->setEnabled(false);
+    open_local_folder_toolbar_action_->setEnabled(false);
+    unsync_action_->setEnabled(false);
+    resync_action_->setEnabled(false);
+    set_sync_interval_action_->setEnabled(false);
+    toggle_auto_sync_action_->setEnabled(false);
+    view_on_web_action_->setEnabled(false);
+    open_in_filebrowser_action_->setEnabled(false);
+    show_detail_action_->setEnabled(false);
+}
+
+void RepoTreeView::saveExpandedCategries()
+{
+    Account account = seafApplet->accountManager()->currentAccount();
+    if (!account.isValid()) {
+        return;
+    }
+    QSettings settings;
+    QStringList cats = expanded_categroies_.toList();
+    settings.beginGroup(kRepoTreeViewSettingsGroup);
+    QString key = QString(kRepoTreeViewSettingsExpandedCategories) + "-" + account.getSignature();
+    settings.setValue(key, cats.join("\t"));
+    settings.endGroup();
+}
+
+void RepoTreeView::showEvent(QShowEvent *event)
+{
+    updateRepoActions();
+}
+
+void RepoTreeView::syncRepoImmediately()
+{
+    LocalRepo repo = qvariant_cast<LocalRepo>(sync_now_action_->data());
+
+    seafApplet->rpcClient()->syncRepoImmediately(repo.id);
+
+    QSortFilterProxyModel *proxy = (QSortFilterProxyModel *)model();
+    RepoTreeModel *tree_model = (RepoTreeModel *)(proxy->sourceModel());
+    tree_model->updateRepoItemAfterSyncNow(repo.id);
+}
+
+void RepoTreeView::cancelDownload()
+{
+    QString error;
+    if (seafApplet->rpcClient()->cancelCloneTask(selected_repo_.id, &error) < 0) {
+        seafApplet->warningBox(tr("Failed to cancel this task:\n\n %1").arg(error), this);
+    } else {
+        seafApplet->messageBox(tr("The download has been canceled"), this);
+    }
+}
+
+void RepoTreeView::expand(const QModelIndex& index, bool remember)
+{
+    QTreeView::expand(index);
+    if (remember) {
+        QStandardItem *item = getRepoItem(index);
+        if (item->type() == REPO_CATEGORY_TYPE) {
+            expanded_categroies_.insert(item->data(Qt::DisplayRole).toString());
+        }
+    }
+}
+
+void RepoTreeView::collapse(const QModelIndex& index, bool remember)
+{
+    QTreeView::collapse(index);
+    if (remember) {
+        QStandardItem *item = getRepoItem(index);
+        if (item->type() == REPO_CATEGORY_TYPE) {
+            expanded_categroies_.remove(item->data(Qt::DisplayRole).toString());
+        }
+    }
+}
+
+void RepoTreeView::restoreExpandedCategries()
+{
+    QSortFilterProxyModel *proxy_model =
+        (QSortFilterProxyModel *)(this->model());
+    RepoTreeModel *tree_model = (RepoTreeModel *)(proxy_model->sourceModel());
+
+    for (int i = 0; i < proxy_model->rowCount(); i++) {
+        QModelIndex index = proxy_model->index(i, 0);
+        QString category = proxy_model->data(index).toString();
+        if (expanded_categroies_.contains(category)) {
+            expand(index, false);
+        } else {
+            collapse(index, false);
+        }
+
+        QStandardItem *item =
+            tree_model->itemFromIndex(proxy_model->mapToSource(index));
+
+        // We need to go one level down if this item is the groups root.
+        if (item->type() == REPO_CATEGORY_TYPE &&
+            ((RepoCategoryItem *)item)->isGroupsRoot()) {
+            for (int j = 0; j < item->rowCount(); j++) {
+                RepoCategoryItem *category_item =
+                    (RepoCategoryItem *)(item->child(j));
+                QModelIndex index = proxy_model->mapFromSource(
+                    tree_model->indexFromItem(category_item));
+                QString category = proxy_model->data(index).toString();
+                if (expanded_categroies_.contains(category)) {
+                    expand(index, false);
+                } else {
+                    collapse(index, false);
+                }
+            }
+        }
+    }
+}
+
+void RepoTreeView::resyncRepo()
+{
+    LocalRepo local_repo = qvariant_cast<LocalRepo>(unsync_action_->data());
+    ServerRepo server_repo = RepoService::instance()->getRepo(local_repo.id);
+
+    SeafileRpcClient *rpc = seafApplet->rpcClient();
+
+    if (!seafApplet->yesOrNoBox(
+            tr("Are you sure to resync the library \"%1\"?").arg(server_repo.name),
+            this)) {
+        return;
+    }
+
+    if (rpc->unsync(server_repo.id) < 0) {
+        seafApplet->warningBox(tr("Failed to unsync library \"%1\"").arg(server_repo.name));
+        return;
+    }
+
+    DownloadRepoDialog dialog(seafApplet->accountManager()->currentAccount(),
+                              RepoService::instance()->getRepo(server_repo.id), QString(), this);
+    dialog.setMergeWithExisting(QFileInfo(local_repo.worktree).dir().absolutePath());
+    if (!server_repo.encrypted) {
+        dialog.setResyncMode();
+    }
+
+    dialog.exec();
+    updateRepoActions();
+}
+
+void RepoTreeView::dropEvent(QDropEvent *event)
+{
+    const QModelIndex index = indexAt(event->pos());
+    QStandardItem *standard_item = getRepoItem(index);
+    if (!standard_item || standard_item->type() != REPO_ITEM_TYPE) {
+        return;
+    }
+    event->accept();
+
+    RepoItem *item = static_cast<RepoItem*>(standard_item);
+    const ServerRepo &repo = item->repo();
+
+    updateDropTarget(QModelIndex());
+
+    const QUrl url = event->mimeData()->urls().at(0);
+    QString local_path = url.toLocalFile();
+#if defined(Q_OS_MAC) && (QT_VERSION <= QT_VERSION_CHECK(5, 4, 0))
+        local_path = utils::mac::fix_file_id_url(local_path);
+#endif
+
+    if (repo.readonly) {
+        // Do not call the `show` method of the dialog. It would show itself if
+        // the task doens't finish within 4 seconds.
+        //
+        // This is also why we can't create the dialog object on stack and use
+        // `dialog.exec()`.
+        CheckRepoRootDirPermDialog *dialog = new CheckRepoRootDirPermDialog(
+            seafApplet->accountManager()->currentAccount(), repo, local_path, this);
+        dialog->setAttribute(Qt::WA_DeleteOnClose);
+        connect(dialog, SIGNAL(finished(int)), this, SLOT(checkRootPermDone()));
+    } else {
+        uploadDroppedFile(repo, local_path);
+    }
+}
+
+void RepoTreeView::checkRootPermDone()
+{
+    CheckRepoRootDirPermDialog *dialog = qobject_cast<CheckRepoRootDirPermDialog *>(sender());
+    if (dialog->hasWritePerm()) {
+        uploadDroppedFile(dialog->repo(), dialog->localPath());
+    } else {
+        seafApplet->warningBox(tr("You do not have permission to upload to this folder"));
+    }
+}
+
+void RepoTreeView::uploadDroppedFile(const ServerRepo& repo, const QString& local_path)
+{
+    const QString file_name = QFileInfo(local_path).fileName();
+    // if the repo is synced
+    LocalRepo local_repo;
+    if (seafApplet->rpcClient()->getLocalRepo(repo.id, &local_repo) >= 0) {
+        QString target_path = QDir(local_repo.worktree).absoluteFilePath(file_name);
+        if (QFileInfo(target_path) == QFileInfo(local_path)) {
+            seafApplet->warningBox(tr("Unable to overwrite file \"%1\" with itself").arg(file_name));
+            return;
+        }
+
+        if (QFileInfo(target_path).exists()) {
+            if (!seafApplet->yesOrNoBox(tr("Are you sure to overwrite the file \"%1\"").arg(file_name)))
+                return;
+            if (!QFile(target_path).remove()) {
+                seafApplet->warningBox(tr("Unable to delete file \"%1\"").arg(file_name));
+                return;
+            }
+        }
+
+        copyFile(local_path, target_path, this);
+
+        return;
+    }
+
+    FileUploadTask *task = new FileUploadTask(seafApplet->accountManager()->currentAccount(),
+          repo.id, "/", local_path, file_name);
+    uploadFileStart(task);
+}
+
+void RepoTreeView::dragMoveEvent(QDragMoveEvent *event)
+{
+    QPoint pos = event->pos();
+    const QModelIndex index = indexAt(pos);
+    QRect rect = visualRect(index);
+
+    // highlight the selected item, and dehightlight when it's over
+    QStandardItem *item = getRepoItem(index);
+    if (item && item->type() == REPO_ITEM_TYPE) {
+        if (changeGrayBackground(pos, rect)) {
+            updateDropTarget(index);
+            event->setDropAction(Qt::CopyAction);
+            event->accept();
+        } else {
+            updateDropTarget(QModelIndex());
+            event->setDropAction(Qt::IgnoreAction);
+            event->accept();
+        }
+    } else {
+       event->setDropAction(Qt::IgnoreAction);
+       event->accept();
+       return;
+    }
+}
+
+void RepoTreeView::dragLeaveEvent(QDragLeaveEvent *event)
+{
+    updateDropTarget(QModelIndex());
+    QTreeView::dragLeaveEvent(event);
+}
+
+void RepoTreeView::dragEnterEvent(QDragEnterEvent *event)
+{
+    if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) {
+        const QUrl url = event->mimeData()->urls().at(0);
+        if (url.scheme() == "file") {
+
+            QString file_name = url.toLocalFile();
+#if defined(Q_OS_MAC) && (QT_VERSION <= QT_VERSION_CHECK(5, 4, 0))
+            file_name = utils::mac::fix_file_id_url(file_name);
+#endif
+
+            if (QFileInfo(file_name).isFile()) {
+                event->setDropAction(Qt::CopyAction);
+                event->accept();
+            }
+        }
+    }
+}
+
+bool RepoTreeView::changeGrayBackground(
+    const QPoint& pos, const QRect& rect) const
+{
+    const int margin = 2;
+    if ((pos.y() - rect.top() > margin) &&
+        (rect.bottom() - pos.y() > margin)) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+void RepoTreeView::updateBackground()
+{
+    if (current_drop_target_.isValid()) {
+        dataChanged(current_drop_target_, current_drop_target_,
+                    QVector<int>(1, Qt::BackgroundRole));
+    }
+
+    if (previous_drop_target_.isValid()) {
+        dataChanged(previous_drop_target_, previous_drop_target_,
+                    QVector<int>(1, Qt::BackgroundRole));
+    }
+}
+
+void RepoTreeView::updateDropTarget(const QModelIndex& index)
+{
+    previous_drop_target_ = current_drop_target_;
+    if (index.isValid() && index == current_drop_target_) {
+        // No need to repaint since the cursor is still with in the same repo
+        // item.
+        return;
+    }
+
+    current_drop_target_ = index;
+    updateBackground();
+}
+
+void RepoTreeView::uploadFileStart(FileUploadTask *task)
+{
+    connect(task, SIGNAL(finished(bool)),
+            this, SLOT(uploadFileFinished(bool)));
+    FileBrowserProgressDialog *dialog = new FileBrowserProgressDialog(task, this);
+
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->show();
+    const QPoint global = this->mapToGlobal(rect().center());
+    dialog->move(global.x() - dialog->width() / 2,
+                 global.y() - dialog->height() / 2);
+    dialog->raise();
+    dialog->activateWindow();
+
+    task->start();
+}
+
+void RepoTreeView::uploadFileFinished(bool success)
+{
+    FileUploadTask *task = qobject_cast<FileUploadTask *>(sender());
+    if (task == NULL)
+        return;
+
+    if (!success) {
+        // if the user cancel the task, don't bother him(or her) with it
+        if (task->error() == FileNetworkTask::TaskCanceled)
+            return;
+        // failed and it is a encrypted repository
+        ServerRepo repo = RepoService::instance()->getRepo(task->repoId());
+        if (repo.encrypted && task->httpErrorCode() == 400) {
+            SetRepoPasswordDialog password_dialog(repo, this);
+            if (password_dialog.exec()) {
+                FileUploadTask *new_task = new FileUploadTask(*task);
+                uploadFileStart(new_task);
+            }
+            return;
+        }
+
+        QString msg = tr("Failed to upload file: %1").arg(task->errorString());
+        seafApplet->warningBox(msg, this);
+    }
+}
+
+void RepoTreeView::copyFileFailed()
+{
+    QString msg = QObject::tr("copy failed");
+    seafApplet->warningBox(msg);
+}
+
+void RepoTreeView::setRepoSyncInterval()
+{
+    LocalRepo local_repo =
+        qvariant_cast<LocalRepo>(set_sync_interval_action_->data());
+
+    int default_interval = 0;
+
+    QString value;
+    if (seafApplet->rpcClient()->getRepoProperty(
+            local_repo.id, kSyncIntervalProperty, &value) == 0) {
+        default_interval = value.toInt();
+    }
+
+    QInputDialog dialog(this);
+    dialog.setInputMode(QInputDialog::IntInput);
+    dialog.setIntMinimum(0);
+    dialog.setIntMaximum(2147483647);
+    dialog.setIntStep(10);
+    dialog.setIntValue(default_interval);
+    dialog.setObjectName("syncIntervalDialog");
+    dialog.setLabelText(tr("Sync Interval (In seconds):"));
+    dialog.setWindowTitle(
+        tr("Set Sync Internval For Library \"%1\"").arg(local_repo.name));
+    dialog.setWindowIcon(QIcon(":/images/seafile.png"));
+    dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
+    dialog.resize(400, 100);
+    if (dialog.exec() != QDialog::Accepted) {
+        return;
+    }
+    int interval = dialog.intValue();
+
+    if (interval != 0 && interval == default_interval) {
+        return;
+    }
+
+    seafApplet->rpcClient()->setRepoProperty(
+        local_repo.id, kSyncIntervalProperty, QString::number(interval));
+}
diff --git a/src/ui/repo-tree-view.h b/src/ui/repo-tree-view.h
new file mode 100644 (file)
index 0000000..0be7bc7
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef SEAFILE_CLIENT_REPO_TREE_VIEW_H
+#define SEAFILE_CLIENT_REPO_TREE_VIEW_H
+
+#include <vector>
+#include <QTreeView>
+#include <QSet>
+
+class QAction;
+class QContextMenuEvent;
+class QEvent;
+class QShowEvent;
+class QHideEvent;
+class QModelIndex;
+class QStandardItem;
+
+class RepoItem;
+class RepoCategoryItem;
+class ServerRepo;
+class LocalRepo;
+
+class ApiError;
+class CloneTasksDialog;
+class FileUploadTask;
+
+class RepoTreeView : public QTreeView {
+    Q_OBJECT
+public:
+    RepoTreeView(QWidget *parent=0);
+
+    std::vector<QAction*> getToolBarActions();
+
+    void expand(const QModelIndex& index, bool remember=true);
+    void collapse(const QModelIndex& index, bool remember=true);
+
+    /**
+     * Restore the expanded repo categories when:
+     * 1. applet startup
+     * 1. restore from filtering repos
+     */
+    void restoreExpandedCategries();
+    const QModelIndex getCurrentDropTarget() const
+        { return current_drop_target_; }
+
+protected:
+    void contextMenuEvent(QContextMenuEvent *event);
+    bool viewportEvent(QEvent *event);
+    void showEvent(QShowEvent *event);
+    void hideEvent(QHideEvent *event);
+    void selectionChanged(const QItemSelection &selected,
+                          const QItemSelection &deselected);
+
+private slots:
+    void downloadRepo();
+    void showRepoDetail();
+    void openLocalFolder();
+    void viewRepoOnWeb();
+    void shareRepoToUser();
+    void shareRepoToGroup();
+    void unshareRepo();
+    void onUnshareSuccess();
+    void onUnshareFailed(const ApiError& error);
+    void openInFileBrowser();
+    void onItemClicked(const QModelIndex& index);
+    void onItemDoubleClicked(const QModelIndex& index);
+    void toggleRepoAutoSync();
+    void unsyncRepo();
+    void syncRepoImmediately();
+    void cancelDownload();
+    void loadExpandedCategries();
+    void saveExpandedCategries();
+    void resyncRepo();
+    void setRepoSyncInterval();
+
+    void checkRootPermDone();
+    void uploadFileStart(FileUploadTask *task);
+    void uploadFileFinished(bool success);
+    void copyFileFailed();
+
+private:
+    QStandardItem* getRepoItem(const QModelIndex &index) const;
+
+    void createActions();
+    QMenu *prepareContextMenu(const RepoItem *item);
+    void updateRepoActions();
+
+    void showRepoItemToolTip(const RepoItem *item,
+                             const QPoint& pos,
+                             const QRect& rect);
+
+    void showRepoCategoryItemToolTip(const RepoCategoryItem *item,
+                                     const QPoint& pos,
+                                     const QRect& rect);
+
+    void dropEvent(QDropEvent *event);
+    void dragMoveEvent(QDragMoveEvent *event);
+    void dragEnterEvent(QDragEnterEvent *event);
+    void dragLeaveEvent(QDragLeaveEvent *event);
+    bool changeGrayBackground(const QPoint& pos,
+                              const QRect& rect) const;
+    void updateBackground();
+    void updateDropTarget(const QModelIndex& index);
+    void shareRepo(bool to_group);
+    void uploadDroppedFile(const ServerRepo& repo, const QString& path);
+    void unsyncRepoImpl(const LocalRepo& repo);
+
+    QAction *download_action_;
+    QAction *download_toolbar_action_;
+    QAction *show_detail_action_;
+    QAction *open_local_folder_action_;
+    QAction *open_local_folder_toolbar_action_;
+    QAction *unsync_action_;
+    QAction *view_on_web_action_;
+    QAction *share_repo_to_user_action_;
+    QAction *share_repo_to_group_action_;
+    QAction *open_in_filebrowser_action_;
+    QAction *unshare_action_;
+    QAction *toggle_auto_sync_action_;
+    QAction *sync_now_action_;
+    QAction *cancel_download_action_;
+    QAction *resync_action_;
+    QAction *set_sync_interval_action_;
+
+    QSet<QString> expanded_categroies_;
+
+    QModelIndex current_drop_target_;
+    QModelIndex previous_drop_target_;
+};
+
+#endif // SEAFILE_CLIENT_REPO_TREE_VIEW_H
diff --git a/src/ui/repos-tab.cpp b/src/ui/repos-tab.cpp
new file mode 100644 (file)
index 0000000..0021c0b
--- /dev/null
@@ -0,0 +1,176 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QTimer>
+#include <QStackedWidget>
+#include <QSortFilterProxyModel>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "repo-service.h"
+#include "repo-tree-view.h"
+#include "repo-tree-model.h"
+#include "repo-item-delegate.h"
+#include "api/requests.h"
+#include "api/server-repo.h"
+#include "rpc/local-repo.h"
+#include "loading-view.h"
+#include "logout-view.h"
+#include "QtAwesome.h"
+#include "ui/search-bar.h"
+
+#include "repos-tab.h"
+
+namespace {
+
+const char *kLoadingFaieldLabelName = "loadingFailedText";
+
+enum {
+    INDEX_LOADING_VIEW = 0,
+    INDEX_LOADING_FAILED_VIEW,
+    INDEX_LOGOUT_VIEW,
+    INDEX_REPOS_VIEW
+};
+
+} // namespace
+
+ReposTab::ReposTab(QWidget *parent)
+    : TabView(parent)
+{
+    createRepoTree();
+    createLoadingView();
+    createLoadingFailedView();
+
+    //createLogoutView
+    logout_view_ = new LogoutView;
+    static_cast<LogoutView*>(logout_view_)->setQssStyleForTab();
+
+    filter_text_ = new SearchBar;
+    filter_text_->setPlaceholderText(tr("Search libraries"));
+    connect(filter_text_, SIGNAL(textChanged(const QString&)),
+            this, SLOT(onFilterTextChanged(const QString&)));
+
+    QVBoxLayout *vlayout = (QVBoxLayout *)layout();
+    vlayout->setSpacing(0);
+    vlayout->insertWidget(0, filter_text_);
+
+    mStack->insertWidget(INDEX_LOADING_VIEW, loading_view_);
+    mStack->insertWidget(INDEX_LOADING_FAILED_VIEW, loading_failed_view_);
+    mStack->insertWidget(INDEX_LOGOUT_VIEW, logout_view_);
+    mStack->insertWidget(INDEX_REPOS_VIEW, repos_tree_);
+
+    RepoService *svc = RepoService::instance();
+
+    connect(svc, SIGNAL(refreshSuccess(const std::vector<ServerRepo>&)),
+            this, SLOT(refreshRepos(const std::vector<ServerRepo>&)));
+    connect(svc, SIGNAL(refreshFailed(const ApiError&)),
+            this, SLOT(refreshReposFailed(const ApiError&)));
+
+    refresh();
+}
+
+void ReposTab::createRepoTree()
+{
+    repos_tree_ = new RepoTreeView(this);
+    repos_model_ = new RepoTreeModel(this);
+    repos_model_->setTreeView(repos_tree_);
+
+    filter_model_ = new RepoFilterProxyModel(this);
+    filter_model_->setSourceModel(repos_model_);
+    filter_model_->setDynamicSortFilter(true);
+    repos_tree_->setModel(filter_model_);
+    repos_tree_->setItemDelegate(new RepoItemDelegate(repos_tree_));
+}
+
+void ReposTab::createLoadingView()
+{
+    loading_view_ = new LoadingView;
+    static_cast<LoadingView*>(loading_view_)->setQssStyleForTab();
+}
+
+void ReposTab::createLoadingFailedView()
+{
+    loading_failed_view_ = new QWidget(this);
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    loading_failed_view_->setLayout(layout);
+
+    QLabel *label = new QLabel;
+    label->setObjectName(kLoadingFaieldLabelName);
+    QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("retry"));
+    QString label_text = tr("Failed to get libraries information<br/>"
+                            "Please %1").arg(link);
+    label->setText(label_text);
+    label->setAlignment(Qt::AlignCenter);
+
+    connect(label, SIGNAL(linkActivated(const QString&)),
+            this, SLOT(refresh()));
+
+    layout->addWidget(label);
+}
+
+void ReposTab::refreshRepos(const std::vector<ServerRepo>& repos)
+{
+    repos_model_->setRepos(repos);
+    onFilterTextChanged(filter_text_->text());
+    filter_text_->setVisible(true);
+    mStack->setCurrentIndex(INDEX_REPOS_VIEW);
+}
+
+void ReposTab::refreshReposFailed(const ApiError& error)
+{
+    qDebug("failed to refresh repos");
+
+    if (mStack->currentIndex() == INDEX_LOADING_VIEW) {
+        mStack->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+    }
+}
+
+std::vector<QAction*> ReposTab::getToolBarActions()
+{
+    return repos_tree_->getToolBarActions();
+}
+
+void ReposTab::showLoadingView()
+{
+    filter_text_->setVisible(false);
+    mStack->setCurrentIndex(INDEX_LOADING_VIEW);
+}
+
+void ReposTab::refresh()
+{
+    if (!seafApplet->accountManager()->hasAccount() ||
+        !seafApplet->accountManager()->accounts().front().isValid()) {
+        mStack->setCurrentIndex(INDEX_LOGOUT_VIEW);
+        return;
+    }
+    filter_text_->clear();
+    showLoadingView();
+    RepoService::instance()->refresh(true);
+}
+
+void ReposTab::startRefresh()
+{
+    RepoService::instance()->start();
+}
+
+void ReposTab::stopRefresh()
+{
+    RepoService::instance()->stop();
+}
+
+void ReposTab::onFilterTextChanged(const QString& text)
+{
+    repos_model_->onFilterTextChanged(text);
+    filter_model_->setFilterText(text.trimmed());
+    filter_model_->sort(0);
+    if (text.isEmpty()) {
+        repos_tree_->restoreExpandedCategries();
+    } else {
+        repos_tree_->expandAll();
+    }
+}
diff --git a/src/ui/repos-tab.h b/src/ui/repos-tab.h
new file mode 100644 (file)
index 0000000..0daf2d3
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef SEAFILE_CLIENT_UI_REPOS_TAB_H
+#define SEAFILE_CLIENT_UI_REPOS_TAB_H
+
+#include <QLineEdit>
+
+#include "tab-view.h"
+
+class QTimer;
+class QToolButton;
+
+class RepoTreeModel;
+class RepoFilterProxyModel;
+class RepoTreeView;
+class ServerRepo;
+class ListReposRequest;
+class ApiError;
+class SearchBar;
+
+/**
+ * The repos list tab
+ */
+class ReposTab : public TabView {
+    Q_OBJECT
+public:
+    explicit ReposTab(QWidget *parent=0);
+
+    std::vector<QAction*> getToolBarActions();
+
+public slots:
+    void refresh();
+
+protected:
+    void startRefresh();
+    void stopRefresh();
+
+private slots:
+    void refreshRepos(const std::vector<ServerRepo>& repos);
+    void refreshReposFailed(const ApiError& error);
+    void onFilterTextChanged(const QString& text);
+
+private:
+    void createRepoTree();
+    void createLoadingView();
+    void createLoadingFailedView();
+    void showLoadingView();
+
+    RepoTreeModel *repos_model_;
+    RepoFilterProxyModel *filter_model_;
+
+    RepoTreeView *repos_tree_;
+    QWidget *loading_view_;
+    QWidget *loading_failed_view_;
+    QWidget *logout_view_;
+
+    SearchBar *filter_text_;
+
+    ListReposRequest *list_repo_req_;
+};
+
+#endif // SEAFILE_CLIENT_UI_REPOS_TAB_H
diff --git a/src/ui/seafile-tab-widget.cpp b/src/ui/seafile-tab-widget.cpp
new file mode 100644 (file)
index 0000000..cd20bb5
--- /dev/null
@@ -0,0 +1,158 @@
+#include <cstdio>
+#include <iostream>
+#include <QLabel>
+#include <QPaintEvent>
+#include <QStylePainter>
+#include <QStyleOptionTabV3>
+#include <QPixmap>
+#include <QIcon>
+#include <QStackedLayout>
+#include <QVBoxLayout>
+
+#include "utils/paint-utils.h"
+
+#include "seafile-tab-widget.h"
+
+namespace {
+
+const int kTabIconSize = 24;
+
+const char *kTabsBackgroundColor = "white";
+const char *kSelectedTabBorderBottomColor = "#D58747";
+const char *kBorderColor = "#DCDCDE";
+const int kSelectedTabBorderBottomWidth = 3;
+const int kSelectedTabBorderBottomHeightAlpha = 2;
+const int kSelectedTabBorderBottomWidthAlpha = 20;
+
+} // namespace
+
+SeafileTabBar::SeafileTabBar(QWidget *parent)
+    : QTabBar(parent)
+{
+    setMinimumSize(0, 48);
+}
+
+void SeafileTabBar::addTab(const QString& text,
+                           const QString& icon_path,
+                           const QString& highlighted_icon)
+{
+    int index = QTabBar::addTab(text);
+    setTabToolTip(index, text);
+    icons_.push_back(icon_path);
+    highlighted_icons_.push_back(highlighted_icon);
+}
+
+void SeafileTabBar::paintEvent(QPaintEvent *event)
+{
+    QStylePainter p(this);
+    QPainter painter;
+    painter.begin(this);
+
+    for (int index = 0, total = count(); index < total; index++) {
+        QRect rect = tabRect(index);
+        rect.adjust(0, 0, 0, 12);
+
+        // QStyleOptionTabV3 tab;
+        // initStyleOption(&tab, index);
+
+        // Draw the tab background
+        painter.fillRect(rect, QColor(kTabsBackgroundColor));
+
+        // Draw the tab icon in the center
+        QPoint top_left;
+        top_left.setX(rect.topLeft().x() + ((rect.width() - kTabIconSize) / 2));
+        top_left.setY(rect.topLeft().y() + ((rect.height() - kTabIconSize) / 2) + 2);
+
+        QIcon icon(currentIndex() == index ? highlighted_icons_[index]
+                                           : icons_[index]);
+        QRect icon_rect(top_left, QSize(kTabIconSize, kTabIconSize));
+        QPixmap icon_pixmap(icon.pixmap(QSize(kTabIconSize, kTabIconSize)));
+        painter.drawPixmap(icon_rect, icon_pixmap);
+
+        // int indicator_width = count() * rect.width() / 8;
+
+        // Draw the selected tab indicator
+        if (currentIndex() == index) {
+            // top_left.setX(rect.bottomLeft().x() + (rect.width() / 2) - (indicator_width / 2));
+            top_left.setX(rect.bottomLeft().x() + (rect.width() / 2) -
+                          (kSelectedTabBorderBottomWidthAlpha / 2));
+            // top_left.setY(rect.bottomLeft().y() - kSelectedTabBorderBottomHeightAlpha + 1);
+            top_left.setY(rect.topLeft().y() + ((rect.height() - kTabIconSize) / 2) +
+                          + 2 + kTabIconSize + 4);
+            QRect border_bottom_rect(top_left, QSize(kSelectedTabBorderBottomWidthAlpha,
+                                                     kSelectedTabBorderBottomHeightAlpha));
+            painter.fillRect(border_bottom_rect, QColor(kSelectedTabBorderBottomColor));
+        }
+    }
+
+    // draw border
+    QPen borderPen(QColor(kBorderColor), 1);
+    painter.save();
+    painter.setPen(borderPen);
+    painter.drawLine(rect().topLeft(), rect().topRight());
+    painter.restore();
+}
+
+
+SeafileTabWidget::SeafileTabWidget(QWidget *parent)
+    : QWidget(parent)
+{
+    layout_ = new QVBoxLayout;
+    layout_->setContentsMargins(0, 0, 0, 0);
+    layout_->setSpacing(0);
+    setLayout(layout_);
+
+    tabbar_ = new SeafileTabBar;
+    tabbar_->setExpanding(true);
+
+    // Init content pane
+    pane_ = new QWidget;
+    // for qss style
+    pane_->setObjectName("pane");
+    stack_ = new QStackedLayout;
+    stack_->setContentsMargins(0, 0, 0, 0);
+    pane_->setLayout(stack_);
+
+    layout_->addWidget(tabbar_);
+    // layout_->addLayout(stack_);
+    layout_->addWidget(pane_);
+
+    connect(tabbar_, SIGNAL(currentChanged(int)),
+            stack_, SLOT(setCurrentIndex(int)));
+
+    connect(tabbar_, SIGNAL(currentChanged(int)),
+            this, SIGNAL(currentTabChanged(int)));
+}
+
+void SeafileTabWidget::addTab(QWidget* tab,
+                              const QString& text,
+                              const QString& icon_path,
+                              const QString& highlighted_icon)
+{
+    tabbar_->addTab(text, icon_path, highlighted_icon);
+    stack_->addWidget(tab);
+}
+
+int SeafileTabWidget::currentIndex() const
+{
+    return stack_->currentIndex();
+}
+
+void SeafileTabWidget::adjustTabsWidth(int full_width)
+{
+    int tab_width = (full_width / tabbar_->count()) - 1;
+    QString style("QTabBar::tab { min-width: %1px; }");
+    style = style.arg(tab_width);
+    setStyleSheet(style);
+}
+
+void SeafileTabWidget::removeTab(int index, QWidget *widget)
+{
+    tabbar_->removeTab(index);
+    stack_->removeWidget(widget);
+}
+
+int SeafileTabWidget::count() const
+{
+    return tabbar_->count();
+}
diff --git a/src/ui/seafile-tab-widget.h b/src/ui/seafile-tab-widget.h
new file mode 100644 (file)
index 0000000..c3f70d5
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef SEAFILE_CLIENT_UI_SEAFILE_TAB_BAR_H
+#define SEAFILE_CLIENT_UI_SEAFILE_TAB_BAR_H
+
+#include <QTabBar>
+#include <vector>
+
+class QPaintEvent;
+class QVBoxLayout;
+class QStackedLayout;
+
+/**
+ * Custom tabbar used in the custom tab widget
+ */
+class SeafileTabBar : public QTabBar
+{
+    Q_OBJECT
+public:
+    SeafileTabBar(QWidget* parent = 0);
+
+    void paintEvent(QPaintEvent* event);
+
+    void addTab(const QString& text,
+                const QString& icon_path,
+                const QString& highlighted_icon);
+
+private:
+    std::vector<QString> icons_;
+    std::vector<QString> highlighted_icons_;
+};
+
+/**
+ * Custom tab widget, allow the tabbar to expand fully
+ */
+class SeafileTabWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    SeafileTabWidget(QWidget* parent = 0);
+
+    void addTab(QWidget* tab,
+                const QString& text,
+                const QString& icon_path,
+                const QString& highlighted_icon);
+
+    void removeTab(int index, QWidget* widget);
+
+    void adjustTabsWidth(int full_width);
+
+    int currentIndex() const;
+
+    int count() const;
+
+signals:
+    void currentTabChanged(int index);
+
+private:
+    QVBoxLayout* layout_;
+
+    SeafileTabBar* tabbar_;
+
+    QWidget* pane_;
+
+    QStackedLayout* stack_;
+};
+
+
+#endif // SEAFILE_CLIENT_UI_SEAFILE_TAB_BAR_H
diff --git a/src/ui/search-bar.cpp b/src/ui/search-bar.cpp
new file mode 100644 (file)
index 0000000..2b87f07
--- /dev/null
@@ -0,0 +1,79 @@
+#include <QToolButton>
+#include <QLabel>
+
+#include "search-bar.h"
+
+namespace {
+
+const int kMarginRightSearchBar = 16;
+const int kMarginBottom = 5;
+const int kHMargin = 10;
+
+} // namespace
+
+SearchBar::SearchBar(QWidget *parent)
+    : QLineEdit(parent)
+{
+    setObjectName("mSearchBar");
+
+    // This property was introduced in Qt 5.2.
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
+    setClearButtonEnabled(false);
+#endif
+#ifdef Q_OS_MAC
+    setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+
+    placeholder_label_ = new QLabel(this);
+
+    clear_button_ = new QToolButton(this);
+    QIcon icon(":/images/cancel.png");
+    clear_button_size_ = 12;
+    clear_button_->setIcon(icon);
+    clear_button_->setIconSize(QSize(clear_button_size_, clear_button_size_));
+    clear_button_->setCursor(Qt::ArrowCursor);
+    clear_button_->setStyleSheet("QToolButton { border: 0px; }");
+    clear_button_->hide();
+    connect(clear_button_, SIGNAL(clicked()),
+            this, SLOT(clear()));
+
+    connect(this, SIGNAL(textChanged(const QString&)),
+            this, SLOT(onTextChanged(const QString&)));
+
+    const QString style = QString(" QLineEdit#mSearchBar { "
+                                      " padding-right: %1px; "
+                                      " padding-left: %2px; } " )
+                                  .arg(clear_button_size_ + kHMargin)
+                                  .arg(kHMargin);
+    setStyleSheet(style);
+}
+
+void SearchBar::paintEvent(QPaintEvent* event)
+{
+    QLineEdit::paintEvent(event);
+}
+
+void SearchBar::resizeEvent(QResizeEvent* event)
+{
+    clear_button_->move(rect().right() - kMarginRightSearchBar
+                        - kHMargin - clear_button_size_ - 12,
+                        (rect().bottom() - clear_button_size_) / 2);
+    int label_height = placeholder_label_->height();
+    int label_width = placeholder_label_->width();
+    placeholder_label_->move((rect().right() - label_width) / 2,
+                             (rect().bottom()  -  label_height) / 2);
+}
+
+void SearchBar::onTextChanged(const QString& text)
+{
+    clear_button_->setVisible(!text.isEmpty());
+    placeholder_label_->setVisible(text.isEmpty());
+}
+
+void SearchBar::setPlaceholderText(const QString& text)
+{
+    placeholder_label_->setText(text);
+    placeholder_label_->setStyleSheet("QLabel { font-size: 13px;"
+                                              " color: #AAAAAA; }");
+    placeholder_label_->show();
+}
diff --git a/src/ui/search-bar.h b/src/ui/search-bar.h
new file mode 100644 (file)
index 0000000..c44ea2c
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SEAFILE_CLIENT_SEARCH_BAR_H_
+#define SEAFILE_CLIENT_SEARCH_BAR_H_
+
+#include <QWidget>
+#include <QLineEdit>
+
+class QToolButton;
+class QLabel;
+
+class SearchBar : public QLineEdit
+{
+    Q_OBJECT
+public:
+    SearchBar(QWidget *parent=0);
+    void setPlaceholderText(const QString& text);
+
+private slots:
+    void onTextChanged(const QString& text);
+
+private:
+    Q_DISABLE_COPY(SearchBar)
+
+    void paintEvent(QPaintEvent* event);
+    void resizeEvent(QResizeEvent* event);
+
+    int clear_button_size_;
+    QToolButton *clear_button_;
+    QLabel *placeholder_label_;
+};
+
+#endif // SEAFILE_CLIENT_SEARCH_BAR_H_
diff --git a/src/ui/search-tab-items.cpp b/src/ui/search-tab-items.cpp
new file mode 100644 (file)
index 0000000..a0d9da3
--- /dev/null
@@ -0,0 +1,300 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "ui/search-tab.h"
+#include "ui/search-tab-items.h"
+#include "ui/main-window.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/paint-utils.h"
+#include "seafile-applet.h"
+#include "api/requests.h"
+#include "repo-service.h"
+
+namespace {
+const int kMarginLeft = 5;
+const int kMarginRight = 5;
+const int kMarginTop = 5;
+const int kMarginBottom = 5;
+const int kPadding = 5;
+
+const int kFileIconHeight = 36;
+const int kFileIconWidth = 36;
+const int kFileNameWidth = 210;
+const int kFileNameHeight = 30;
+
+const int kSubtitleHeight = 16;
+
+const int kMarginBetweenFileIconAndName = 10;
+
+const char *kFileNameColor = "#3F3F3F";
+const char *kFileNameColorHighlighted = "#544D49";
+const char *kSubtitleColor = "#959595";
+const char *kSubtitleColorHighlighted = "#9D9B9A";
+const int kFileNameFontSize = 14;
+const int kSubtitleFontSize = 11;
+
+const char *kFileItemBackgroundColor = "white";
+const char *kFileItemBackgroundColorHighlighted = "#F9E0C7";
+
+const char *kItemBottomBorderColor = "#EEE";
+
+const int PLACE_HOLDER_TYPE = 999;
+
+static inline const QListWidgetItem *getItem(const QModelIndex &index)
+{
+    const SearchResultListModel *model = static_cast<const SearchResultListModel*>(index.model());
+    return model->item(index);
+}
+static inline FileSearchResult getSearchResult(const QModelIndex &index)
+{
+    const QListWidgetItem *item = getItem(index);
+    if (!item)
+        return FileSearchResult();
+    return item->data(Qt::UserRole).value<FileSearchResult>();
+}
+} // anonymous namespace
+
+void SearchResultItemDelegate::paint(QPainter *painter,
+                                     const QStyleOptionViewItem &option,
+                                     const QModelIndex &index) const {
+    const SearchResultListModel *model = static_cast<const SearchResultListModel*>(index.model());
+    const QListWidgetItem* item = getItem(index);
+    if (item && item->type() == PLACE_HOLDER_TYPE) {
+        // This is the place holder item for the "load more" button
+        return;
+    }
+    QBrush backBrush;
+    bool selected = false;
+    FileSearchResult file = getSearchResult(index);
+
+    if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) {
+        backBrush = QColor(kFileItemBackgroundColorHighlighted);
+        selected = true;
+    } else {
+        backBrush = QColor(kFileItemBackgroundColor);
+    }
+
+    //
+    // draw item's background
+    //
+    painter->save();
+    painter->fillRect(option.rect, backBrush);
+    painter->restore();
+
+    QIcon icon = model->data(index, Qt::DecorationRole).value<QIcon>();
+    QPixmap pixmap(icon.pixmap(QSize(kFileIconWidth, kFileIconHeight)));
+    //
+    // paint file icon
+    //
+    QPoint file_icon_pos(kMarginLeft + kPadding, kMarginTop + kPadding);
+    file_icon_pos += option.rect.topLeft();
+    painter->save();
+    painter->drawPixmap(file_icon_pos, pixmap);
+    painter->restore();
+
+    // Calculate the file column by the delta of mainwindow's width
+    QString title = file.name;
+
+    const int file_name_width = kFileNameWidth
+      + seafApplet->mainWindow()->width() - seafApplet->mainWindow()->minimumWidth();
+    painter->save();
+    QPoint file_name_pos = file_icon_pos + QPoint(kFileIconWidth + kMarginBetweenFileIconAndName, -kPadding);
+    QRect file_name_rect(file_name_pos, QSize(file_name_width, kFileNameHeight));
+    painter->setPen(QColor(selected ? kFileNameColorHighlighted : kFileNameColor));
+    painter->setFont(changeFontSize(painter->font(), kFileNameFontSize));
+
+    painter->drawText(file_name_rect,
+                      Qt::AlignLeft | Qt::AlignTop,
+                      fitTextToWidth(title, option.font, file_name_width),
+                      &file_name_rect);
+    painter->restore();
+
+    //
+    // Paint repo_name
+    //
+    int count_of_splash = file.fullpath.endsWith("/") ? 2 : 1;
+    QString subtitle = file.fullpath.mid(1, file.fullpath.size() - count_of_splash - file.name.size());
+    if (!subtitle.isEmpty())
+        subtitle = file.repo_name + "/" + subtitle.left(subtitle.size() - 1);
+    else
+        subtitle = file.repo_name;
+
+    painter->save();
+    QPoint file_desc_pos = file_name_rect.bottomLeft() + QPoint(0, kPadding / 2);
+    QRect file_desc_rect(file_desc_pos, QSize(file_name_width, kSubtitleHeight));
+    painter->setFont(changeFontSize(painter->font(), kSubtitleFontSize));
+    painter->setPen(QColor(selected ? kSubtitleColorHighlighted : kSubtitleColor));
+    painter->drawText(file_desc_rect,
+                      Qt::AlignLeft | Qt::AlignTop,
+                      fitTextToWidth(subtitle, option.font, file_name_width),
+                      &file_desc_rect);
+    painter->restore();
+
+    //
+    // Paint file description
+    //
+    QString size, mtime;
+
+    size = readableFileSize(file.size);
+    mtime = translateCommitTime(file.last_modified);
+
+    QString extra_title = size + "  " + mtime;
+
+    painter->save();
+    QPoint file_extra_pos = file_desc_rect.bottomLeft() + QPoint(0, kPadding / 2 + 2);
+    QRect file_extra_rect(file_extra_pos, QSize(file_name_width, kSubtitleHeight));
+    painter->setFont(changeFontSize(painter->font(), kSubtitleFontSize));
+    painter->setPen(QColor(selected ? kSubtitleColorHighlighted : kSubtitleColor));
+    painter->drawText(file_extra_rect,
+                      Qt::AlignLeft | Qt::AlignTop,
+                      fitTextToWidth(extra_title, option.font, file_name_width),
+                      &file_extra_rect);
+    painter->restore();
+
+    //
+    // Draw the bottom border lines
+    //
+    painter->save();
+    painter->setPen(QPen(QColor(kItemBottomBorderColor), 1, Qt::SolidLine));
+    painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
+    painter->restore();
+}
+
+QSize SearchResultItemDelegate::sizeHint(const QStyleOptionViewItem &option,
+                                         const QModelIndex &index) const {
+
+    const QListWidgetItem* item = getItem(index);
+    if (!item)
+        return QStyledItemDelegate::sizeHint(option, index);
+
+    return QSize(kMarginLeft + kFileIconWidth + kMarginBetweenFileIconAndName + kFileNameWidth + kMarginRight + kPadding * 2,
+                 kFileIconHeight + kPadding * 3 + kMarginTop + kMarginBottom);
+}
+
+SearchResultListView::SearchResultListView(QWidget* parent) : QListView(parent)
+{
+#if defined(Q_OS_MAC)
+    setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+    createActions();
+}
+
+void SearchResultListView::createActions()
+{
+    open_parent_dir_action_ = new QAction(tr("&Show in folder"), this);
+    open_parent_dir_action_->setIcon(QIcon(":/images/toolbar/file-gray.png"));
+    open_parent_dir_action_->setIconVisibleInMenu(true);
+    open_parent_dir_action_->setStatusTip(tr("Show in folder"));
+    connect(open_parent_dir_action_,
+            SIGNAL(triggered()),
+            this,
+            SLOT(openParentDir()));
+}
+
+void SearchResultListView::contextMenuEvent(QContextMenuEvent* event)
+{
+    QPoint pos = event->pos();
+    QModelIndex index = indexAt(pos);
+    if (!index.isValid()) {
+        return;
+    }
+
+    const QListWidgetItem* item = getItem(index);
+    if (!item) {
+        return;
+    }
+
+    updateActions();
+    QMenu* menu = prepareContextMenu();
+    pos = viewport()->mapToGlobal(pos);
+    menu->exec(pos);
+}
+
+QMenu* SearchResultListView::prepareContextMenu()
+{
+    QMenu* menu = new QMenu(this);
+    menu->addAction(open_parent_dir_action_);
+    return menu;
+}
+
+void SearchResultListView::updateActions()
+{
+    QModelIndexList indexes = selectionModel()->selection().indexes();
+    if (indexes.size() != 0) {
+        FileSearchResult file = getSearchResult(indexes.at(0));
+        open_parent_dir_action_->setData(QVariant::fromValue(file));
+        open_parent_dir_action_->setEnabled(true);
+    } else {
+        open_parent_dir_action_->setEnabled(false);
+    }
+}
+
+void SearchResultListView::openParentDir()
+{
+    FileSearchResult result =
+        qvariant_cast<FileSearchResult>(open_parent_dir_action_->data());
+    RepoService::instance()->openFolder(result.repo_id,
+                                        ::getParentPath(result.fullpath));
+}
+
+SearchResultListModel::SearchResultListModel() : QAbstractListModel()
+{
+    has_more_ = false;
+}
+
+void SearchResultListModel::addItem(QListWidgetItem *item)
+{
+    items_.push_back(item);
+    emit dataChanged(index(items_.size() - 1), index(items_.size() - 1));
+}
+
+const QModelIndex SearchResultListModel::updateSearchResults(
+    const std::vector<QListWidgetItem *> &items,
+    bool is_loading_more,
+    bool has_more)
+{
+    int first_new_item = 0;
+
+    beginResetModel();
+    if (!is_loading_more) {
+        first_new_item = 0;
+        clear();
+    } else {
+        if (items_.size() > 0 && items_[items_.size() - 1]->type() == PLACE_HOLDER_TYPE) {
+            QListWidgetItem *old_place_holder = items_[items_.size() - 1];
+            items_.pop_back();
+            first_new_item = items_.size();
+
+            delete old_place_holder;
+        }
+    }
+
+    items_.insert(items_.end(), items.begin(), items.end());
+
+    // place holder for the "load more" button
+    QListWidgetItem *load_more_place_holder = new QListWidgetItem(nullptr, PLACE_HOLDER_TYPE);
+    items_.push_back(load_more_place_holder);
+
+    load_more_index_ = QModelIndex();
+    if (has_more) {
+        load_more_index_ = index(items_.size() - 1);
+    }
+
+    endResetModel();
+
+    if (first_new_item) {
+        return index(first_new_item);
+    }
+    return QModelIndex();
+}
+
+int SearchResultListModel::rowCount(const QModelIndex &index) const
+{
+    return items_.size();
+}
diff --git a/src/ui/search-tab-items.h b/src/ui/search-tab-items.h
new file mode 100644 (file)
index 0000000..13a7c50
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef SEAFILE_CLIENT_UI_SEARCH_TAB_ITEMS_H
+#define SEAFILE_CLIENT_UI_SEARCH_TAB_ITEMS_H
+
+#include <vector>
+#include <QAbstractItemModel>
+#include <QListWidgetItem>
+#include <QListView>
+#include <QStyledItemDelegate>
+
+class QAction;
+class QMenu;
+
+class SearchResultListView : public QListView {
+    Q_OBJECT
+public:
+    SearchResultListView(QWidget *parent=0);
+
+protected:
+    void contextMenuEvent(QContextMenuEvent *event);
+
+private slots:
+    void openParentDir();
+
+private:
+    void createActions();
+    void updateActions();
+    QMenu *prepareContextMenu();
+
+    QAction *open_parent_dir_action_;
+};
+
+class SearchResultListModel : public QAbstractListModel {
+    Q_OBJECT
+public:
+    SearchResultListModel();
+    ~SearchResultListModel()
+    {
+        clear();
+    }
+    int rowCount(const QModelIndex &index) const;
+    const QListWidgetItem* item(const QModelIndex& index) const
+    {
+        if (!index.isValid() || index.row() >= (int)items_.size())
+            return NULL;
+        return items_[index.row()];
+    }
+    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+    {
+        if (!index.isValid() || index.row() >= (int)items_.size())
+            return QVariant();
+        return items_[index.row()]->data(role);
+    }
+    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) {
+        if (index.row() >= (int)items_.size())
+            return false;
+        if (items_[index.row()]->data(role) == value)
+            return true;
+        items_[index.row()]->setData(role, value);
+        emit dataChanged(index, index);
+        return true;
+    }
+    void clear()
+    {
+        for (unsigned i = 0 ; i < items_.size(); ++i) {
+            delete items_[i];
+        }
+        items_.clear();
+    }
+
+    void addItem(QListWidgetItem *item);
+    const QModelIndex updateSearchResults(const std::vector<QListWidgetItem *> &items, bool is_loading_more, bool has_more);
+
+    const QModelIndex loadMoreIndex() const { return load_more_index_; }
+
+private:
+    std::vector<QListWidgetItem*> items_;
+    bool has_more_;
+    QModelIndex load_more_index_;
+};
+
+class SearchResultItemDelegate : public QStyledItemDelegate {
+public:
+    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+};
+
+
+#endif // SEAFILE_CLIENT_UI_SEARCH_TAB_ITEMS_H
diff --git a/src/ui/search-tab.cpp b/src/ui/search-tab.cpp
new file mode 100644 (file)
index 0000000..27ddd82
--- /dev/null
@@ -0,0 +1,286 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "api/requests.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "repo-service.h"
+#include "loading-view.h"
+#include "logout-view.h"
+#include "utils/file-utils.h"
+#include "utils/paint-utils.h"
+#include "ui/search-bar.h"
+
+#include "ui/search-tab.h"
+#include "ui/search-tab-items.h"
+
+namespace {
+const int kMinimumKeywordLength = 3;
+const int kInputDelayInterval = 300;
+const char *kLoadingFailedLabelName = "loadingFailedText";
+
+enum {
+    INDEX_WAITING_VIEW = 0,
+    INDEX_LOADING_VIEW,
+    INDEX_LOADING_FAILED_VIEW,
+    INDEX_LOGOUT_VIEW,
+    INDEX_SEARCH_VIEW,
+};
+
+} // anonymous namespace
+
+SearchTab::SearchTab(QWidget *parent)
+    : TabView(parent), last_modified_(0), request_(NULL), nth_page_(1)
+{
+    createSearchView();
+    createLoadingView();
+    createLoadingFailedView();
+
+    //createLogoutView
+    logout_view_ = new LogoutView;
+    static_cast<LogoutView*>(logout_view_)->setQssStyleForTab();
+
+    mStack->insertWidget(INDEX_WAITING_VIEW, waiting_view_);
+    mStack->insertWidget(INDEX_LOADING_VIEW, loading_view_);
+    mStack->insertWidget(INDEX_LOADING_FAILED_VIEW, loading_failed_view_);
+    mStack->insertWidget(INDEX_LOGOUT_VIEW, logout_view_);
+    mStack->insertWidget(INDEX_SEARCH_VIEW, search_view_);
+
+    connect(line_edit_, SIGNAL(textChanged(const QString&)),
+            this, SLOT(doSearch(const QString&)));
+
+    connect(search_view_, SIGNAL(doubleClicked(const QModelIndex&)),
+            this, SLOT(onDoubleClicked(const QModelIndex&)));
+
+    search_timer_ = new QTimer(this);
+    connect(search_timer_, SIGNAL(timeout()), this, SLOT(doRealSearch()));
+    search_timer_->start(kInputDelayInterval);
+}
+
+SearchTab::~SearchTab()
+{
+    stopRefresh();
+    delete search_model_;
+}
+
+void SearchTab::reset()
+{
+    stopRefresh();
+    line_edit_->setText("");
+    mStack->setCurrentIndex(INDEX_WAITING_VIEW);
+}
+
+void SearchTab::createSearchView()
+{
+    QVBoxLayout *layout = (QVBoxLayout*)this->layout();
+    line_edit_ = new SearchBar;
+    line_edit_->setPlaceholderText(tr("Search files"));
+    layout->insertWidget(0, line_edit_);
+
+    waiting_view_ = new QWidget;
+    waiting_view_->installEventFilter(this);
+
+    search_view_ = new SearchResultListView;
+    search_view_->setObjectName("searchResult");
+#ifdef Q_OS_MAC
+    search_view_->setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+    search_model_ = new SearchResultListModel;
+    search_view_->setModel(search_model_);
+
+    search_delegate_ = new SearchResultItemDelegate;
+
+    delete search_view_->itemDelegate();
+    search_view_->setItemDelegate(search_delegate_);
+}
+
+void SearchTab::createLoadingView()
+{
+    loading_view_ = new LoadingView;
+    static_cast<LoadingView*>(loading_view_)->setQssStyleForTab();
+}
+
+void SearchTab::createLoadingFailedView()
+{
+    loading_failed_view_ = new QWidget(this);
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    loading_failed_view_->setLayout(layout);
+
+    loading_failed_text_ = new QLabel;
+    loading_failed_text_->setObjectName(kLoadingFailedLabelName);
+    loading_failed_text_->setAlignment(Qt::AlignCenter);
+    QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("retry"));
+    QString label_text = tr("Failed to search<br/>"
+                            "Please %1").arg(link);
+    loading_failed_text_->setText(label_text);
+
+    connect(loading_failed_text_, SIGNAL(linkActivated(const QString&)),
+            this, SLOT(refresh()));
+
+    layout->addWidget(loading_failed_text_);
+}
+
+void SearchTab::showLoadingView()
+{
+    mStack->setCurrentIndex(INDEX_LOADING_VIEW);
+}
+
+bool SearchTab::eventFilter(QObject *obj, QEvent *event)
+{
+    if (obj == waiting_view_ && event->type() == QEvent::Paint) {
+        QPainter painter(waiting_view_);
+
+        QPaintEvent *ev = (QPaintEvent*)event;
+        const QSize size(72, 72);
+        const int x = ev->rect().width() / 2 - size.width() / 2;
+        const int y = ev->rect().height() / 2 - size.height() / 2;
+        QRect rect(QPoint(x, y), size);
+
+        // get the device pixel radio from current painter device
+        int scale_factor = 1;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+        scale_factor = globalDevicePixelRatio();
+#endif // QT5
+
+        QPixmap image = QIcon(":/images/main-panel/search-background.png").pixmap(size);
+        painter.drawPixmap(rect, image);
+
+        return true;
+    };
+    return QObject::eventFilter(obj, event);
+}
+
+void SearchTab::refresh()
+{
+    if (!seafApplet->accountManager()->currentAccount().isValid()) {
+        mStack->setCurrentIndex(INDEX_LOGOUT_VIEW);
+        return;
+    }
+    if (!line_edit_->text().isEmpty()) {
+        last_modified_ = 1;
+        doRealSearch();
+    }
+}
+
+void SearchTab::startRefresh()
+{
+    search_timer_->start();
+}
+
+void SearchTab::stopRefresh()
+{
+    search_timer_->stop();
+    if (request_) {
+        request_->deleteLater();
+        request_ = NULL;
+    }
+}
+
+void SearchTab::doSearch(const QString& keyword)
+{
+    // make it search utf-8 charcters
+    if (keyword.toUtf8().size() < kMinimumKeywordLength) {
+        mStack->setCurrentIndex(INDEX_WAITING_VIEW);
+        return;
+    }
+
+    // save for doRealSearch
+    last_modified_ = QDateTime::currentMSecsSinceEpoch();
+}
+
+void SearchTab::doRealSearch(bool load_more)
+{
+    if (!load_more) {
+        // not modified
+        if (last_modified_ == 0)
+            return;
+        // modified too fast
+        if (QDateTime::currentMSecsSinceEpoch() - last_modified_ <= kInputDelayInterval)
+            return;
+    }
+
+    const Account& account = seafApplet->accountManager()->currentAccount();
+
+    if (!account.isValid())
+        return;
+    if (request_) {
+        // request_->abort();
+        request_->deleteLater();
+        request_ = NULL;
+    }
+
+    if (!load_more) {
+        nth_page_ = 1;
+        mStack->setCurrentIndex(INDEX_LOADING_VIEW);
+    } else {
+        nth_page_++;
+    }
+
+    request_ = new FileSearchRequest(account, line_edit_->text(), nth_page_);
+    connect(request_, SIGNAL(success(const std::vector<FileSearchResult>&, bool, bool)),
+            this, SLOT(onSearchSuccess(const std::vector<FileSearchResult>&, bool, bool)));
+    connect(request_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(onSearchFailed(const ApiError&)));
+
+    request_->send();
+
+    // reset
+    last_modified_ = 0;
+}
+
+void SearchTab::onSearchSuccess(const std::vector<FileSearchResult>& results,
+                                bool is_loading_more,
+                                bool has_more)
+{
+    std::vector<QListWidgetItem*> items;
+
+    for (unsigned i = 0; i < results.size(); ++i) {
+        QListWidgetItem *item = new QListWidgetItem(results[i].name);
+        if (results[i].fullpath.endsWith("/"))
+            item->setIcon(QIcon(getIconByFolder()));
+        else
+            item->setIcon(QIcon(getIconByFileName(results[i].name)));
+        item->setData(Qt::UserRole, QVariant::fromValue(results[i]));
+        items.push_back(item);
+    }
+
+    mStack->setCurrentIndex(INDEX_SEARCH_VIEW);
+
+    const QModelIndex first_new_item = search_model_->updateSearchResults(items, is_loading_more, has_more);
+    if (first_new_item.isValid()) {
+        search_view_->scrollTo(first_new_item);
+    }
+
+    if (has_more) {
+        load_more_btn_ = new LoadMoreButton;
+        connect(load_more_btn_, SIGNAL(clicked()),
+                this, SLOT(loadMoreSearchResults()));
+        search_view_->setIndexWidget(
+            search_model_->loadMoreIndex(), load_more_btn_);
+    }
+}
+
+void SearchTab::loadMoreSearchResults()
+{
+    doRealSearch(true);
+}
+
+void SearchTab::onSearchFailed(const ApiError& error)
+{
+    mStack->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+}
+
+void SearchTab::onDoubleClicked(const QModelIndex& index)
+{
+    FileSearchResult result = search_model_->data(index, Qt::UserRole).value<FileSearchResult>();
+    if (result.name.isEmpty() || result.fullpath.isEmpty())
+        return;
+
+    RepoService::instance()->openLocalFile(result.repo_id, result.fullpath);
+}
diff --git a/src/ui/search-tab.h b/src/ui/search-tab.h
new file mode 100644 (file)
index 0000000..e89a1d0
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef SEAFILE_CLIENT_UI_SEARCH_TAB_H
+#define SEAFILE_CLIENT_UI_SEARCH_TAB_H
+#include "tab-view.h"
+
+class QWidget;
+class QLabel;
+class QListView;
+class SearchResultListView;
+class SearchResultListModel;
+class SearchResultItemDelegate;
+class QListWidget;
+class QListWidgetItem;
+class QLineEdit;
+class QTimer;
+class QModelIndex;
+class FileSearchRequest;
+struct FileSearchResult;
+class ApiError;
+class LoadMoreButton;
+class SearchBar;
+
+class SearchTab : public TabView {
+    Q_OBJECT
+public:
+    explicit SearchTab(QWidget *parent = 0);
+    ~SearchTab();
+    void reset();
+
+public slots:
+    void refresh();
+
+protected:
+    void startRefresh();
+    void stopRefresh();
+
+private slots:
+    void doSearch(const QString& keyword);
+    void doRealSearch(bool load_more = false);
+    void loadMoreSearchResults();
+
+    void onDoubleClicked(const QModelIndex& index);
+
+    void onSearchSuccess(const std::vector<FileSearchResult>& results,
+                         bool is_loading_more,
+                         bool has_more);
+    void onSearchFailed(const ApiError& error);
+
+private:
+    void createSearchView();
+    void createLoadingView();
+    void createLoadingFailedView();
+    void showLoadingView();
+
+    bool eventFilter(QObject *obj, QEvent *event);
+
+private:
+    qint64 last_modified_;
+    QTimer *search_timer_;
+    FileSearchRequest *request_;
+
+    QWidget *waiting_view_;
+    QWidget *loading_view_;
+    QWidget *loading_failed_view_;
+    QWidget *logout_view_;
+
+    QLabel *loading_failed_text_;
+    LoadMoreButton *load_more_btn_;
+
+    SearchBar *line_edit_;
+
+    SearchResultItemDelegate *search_delegate_;
+    SearchResultListView *search_view_;
+    SearchResultListModel *search_model_;
+
+    int nth_page_;
+};
+#endif // SEAFILE_CLIENT_UI_SEARCH_TAB_HSEAF
diff --git a/src/ui/server-status-dialog.cpp b/src/ui/server-status-dialog.cpp
new file mode 100644 (file)
index 0000000..95c7e27
--- /dev/null
@@ -0,0 +1,41 @@
+#include "server-status-service.h"
+#include "server-status-dialog.h"
+
+ServerStatusDialog::ServerStatusDialog(QWidget *parent) : QDialog(parent)
+{
+    setupUi(this);
+
+#if defined(Q_OS_MAC)
+    layout()->setContentsMargins(8, 9, 9, 4);
+    layout()->setSpacing(5);
+#endif
+
+    setWindowTitle(tr("Servers connection status"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+    setWindowIcon(QIcon(":/images/seafile.png"));
+
+    refreshStatus();
+
+    connect(ServerStatusService::instance(), SIGNAL(serverStatusChanged()),
+            this, SLOT(refreshStatus()));
+}
+
+void ServerStatusDialog::refreshStatus()
+{
+    mList->clear();
+
+    foreach (const ServerStatus& status, ServerStatusService::instance()->statuses()) {
+        QListWidgetItem *item = new QListWidgetItem(mList);
+        item->setData(Qt::DisplayRole, status.url.host());
+
+        if (status.connected) {
+            item->setData(Qt::DecorationRole, QIcon(":/images/sync/done.png"));
+            item->setData(Qt::ToolTipRole, tr("connected"));
+        } else {
+            item->setData(Qt::DecorationRole, QIcon(":/images/remove-red.png"));
+            item->setData(Qt::ToolTipRole, tr("disconnected"));
+        }
+
+        mList->addItem(item);
+    }
+}
diff --git a/src/ui/server-status-dialog.h b/src/ui/server-status-dialog.h
new file mode 100644 (file)
index 0000000..fee54ac
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SEAFILE_CLIENT_SERVER_STATUS_DIALOG_H
+#define SEAFILE_CLIENT_SERVER_STATUS_DIALOG_H
+
+#include <QDialog>
+#include "ui_server-status-dialog.h"
+
+class ServerStatusDialog : public QDialog,
+                           public Ui::ServerStatusDialog
+{
+    Q_OBJECT
+public:
+    ServerStatusDialog(QWidget *parent=0);
+
+private slots:
+    void refreshStatus();
+
+private:
+    Q_DISABLE_COPY(ServerStatusDialog)
+};
+
+#endif // SEAFILE_CLIENT_SERVER_STATUS_DIALOG_H
diff --git a/src/ui/set-repo-password-dialog.cpp b/src/ui/set-repo-password-dialog.cpp
new file mode 100644 (file)
index 0000000..eda27af
--- /dev/null
@@ -0,0 +1,83 @@
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+
+#include "set-repo-password-dialog.h"
+
+SetRepoPasswordDialog::SetRepoPasswordDialog(const ServerRepo& repo, QWidget *parent)
+    : QDialog(parent),
+      repo_(repo)
+{
+    setupUi(this);
+    setWindowTitle(tr("Please provide the library password"));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    request_ = 0;
+
+    QString name = QString("<b>%1</b>").arg(repo.name);
+    mHintText->setText(tr("Provide the password for library %1").arg(name));
+
+    mErrorText->setText(QString());
+
+    connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkBtnClicked()));
+}
+
+void SetRepoPasswordDialog::onOkBtnClicked()
+{
+    mErrorText->setText(QString());
+
+    password_ = mPassword->text().trimmed();
+
+    if (password_.isEmpty()) {
+        QString msg = tr("Please enter the password");
+        seafApplet->warningBox(msg, this);
+        return;
+    }
+
+    disableInputs();
+
+    const Account& account = seafApplet->accountManager()->currentAccount();
+
+    if (request_) {
+        request_->deleteLater();
+    }
+
+    request_ = new SetRepoPasswordRequest(account, repo_.id, password_);
+    connect(request_, SIGNAL(success()),
+            this, SLOT(accept()));
+    connect(request_, SIGNAL(failed(const ApiError&)),
+            this, SLOT(requestFailed(const ApiError&)));
+
+    request_->send();
+}
+
+void SetRepoPasswordDialog::requestFailed(const ApiError& error)
+{
+    QString msg;
+    if (error.httpErrorCode() == 400) {
+        msg = tr("Incorrect password");
+    } else {
+        msg = tr("Unknown error");
+    }
+
+    mErrorText->setText(msg);
+
+    enableInputs();
+}
+
+void SetRepoPasswordDialog::enableInputs()
+{
+    mOkBtn->setEnabled(true);
+    mCancelBtn->setEnabled(true);
+    mPassword->setEnabled(true);
+}
+
+void SetRepoPasswordDialog::disableInputs()
+{
+    mOkBtn->setEnabled(false);
+    mCancelBtn->setEnabled(false);
+    mPassword->setEnabled(false);
+}
diff --git a/src/ui/set-repo-password-dialog.h b/src/ui/set-repo-password-dialog.h
new file mode 100644 (file)
index 0000000..b6bb19b
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SEAFILE_CLIENT_SET_REPO_PASSWORD_DIALOG_H
+#define SEAFILE_CLIENT_SET_REPO_PASSWORD_DIALOG_H
+
+#include <QDialog>
+#include <QString>
+#include "ui_set-repo-password-dialog.h"
+
+#include "api/server-repo.h"
+
+class Account;
+class ApiError;
+class SetRepoPasswordRequest;
+
+class SetRepoPasswordDialog : public QDialog,
+                              public Ui::SetRepoPasswordDialog
+{
+    Q_OBJECT
+public:
+    SetRepoPasswordDialog(const ServerRepo& repo, QWidget *parent=0);
+    const QString& password() { return password_; }
+
+private slots:
+    void onOkBtnClicked();
+    void requestFailed(const ApiError& error);
+
+private:
+    Q_DISABLE_COPY(SetRepoPasswordDialog);
+
+    void enableInputs();
+    void disableInputs();
+
+    QString password_;
+    SetRepoPasswordRequest *request_;
+    ServerRepo repo_;
+};
+
+#endif // SEAFILE_CLIENT_SET_REPO_PASSWORD_DIALOG_H
diff --git a/src/ui/settings-dialog.cpp b/src/ui/settings-dialog.cpp
new file mode 100644 (file)
index 0000000..a236f9a
--- /dev/null
@@ -0,0 +1,428 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QDebug>
+#include <QSettings>
+
+#include "i18n.h"
+#include "account-mgr.h"
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "settings-mgr.h"
+#include "api/requests.h"
+#include "settings-dialog.h"
+
+#ifdef HAVE_SPARKLE_SUPPORT
+#include "auto-update-service.h"
+#endif
+
+namespace {
+
+const char *kSettingsGroupForSettingsDialog = "SettingsDialog";
+
+} // namespace
+
+SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent)
+{
+    setupUi(this);
+    setWindowTitle(tr("Settings"));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    mAutoStartCheckBox->setText(
+        tr("Auto start %1 after login").arg(getBrand()));
+
+    mHideDockIconCheckBox->setText(
+        tr("Hide %1 Icon from the dock").arg(getBrand()));
+
+    mTabWidget->setCurrentIndex(0);
+
+#ifdef HAVE_SPARKLE_SUPPORT
+    if (!AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
+        mCheckLatestVersionBox->setVisible(false);
+    }
+#endif
+
+    mLanguageComboBox->addItems(I18NHelper::getInstance()->getLanguages());
+    // The range of mProxyPort is set to (0, 65535) in the ui file, so we
+    // don't bother with that here.
+    mProxyMethodComboBox->insertItem(SettingsManager::NoProxy, tr("None"));
+    mProxyMethodComboBox->insertItem(SettingsManager::HttpProxy, tr("HTTP Proxy"));
+    mProxyMethodComboBox->insertItem(SettingsManager::SocksProxy, tr("Socks5 Proxy"));
+    mProxyMethodComboBox->insertItem(SettingsManager::SystemProxy, tr("System Proxy"));
+    connect(mProxyMethodComboBox, SIGNAL(currentIndexChanged(int)),
+            this, SLOT(showHideControlsBasedOnCurrentProxyType(int)));
+    connect(mProxyRequirePassword, SIGNAL(stateChanged(int)),
+            this, SLOT(proxyRequirePasswordChanged(int)));
+
+#if defined(Q_OS_MAC)
+    layout()->setContentsMargins(8, 9, 9, 4);
+    layout()->setSpacing(5);
+
+    mDownloadSpinBox->setAttribute(Qt::WA_MacShowFocusRect, 0);
+    mUploadSpinBox->setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+
+    connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkBtnClicked()));
+}
+
+void SettingsDialog::updateSettings()
+{
+    SettingsManager *mgr = seafApplet->settingsManager();
+    mgr->setNotify(mNotifyCheckBox->checkState() == Qt::Checked);
+    mgr->setAutoStart(mAutoStartCheckBox->checkState() == Qt::Checked);
+    mgr->setHideDockIcon(mHideDockIconCheckBox->checkState() == Qt::Checked);
+    mgr->setSyncExtraTempFile(mSyncExtraTempFileCheckBox->checkState() == Qt::Checked);
+    mgr->setMaxDownloadRatio(mDownloadSpinBox->value());
+    mgr->setMaxUploadRatio(mUploadSpinBox->value());
+    mgr->setHideMainWindowWhenStarted(mHideMainWinCheckBox->checkState() == Qt::Checked);
+    mgr->setAllowInvalidWorktree(mAllowInvalidWorktreeCheckBox->checkState() == Qt::Checked);
+    mgr->setHttpSyncCertVerifyDisabled(mDisableVerifyHttpSyncCert->checkState() == Qt::Checked);
+    mgr->setAllowRepoNotFoundOnServer(mAllowRepoNotFoundCheckBox->checkState() == Qt::Checked);
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+    if(mFinderSyncCheckBox->isEnabled())
+        mgr->setFinderSyncExtension(mFinderSyncCheckBox->checkState() == Qt::Checked);
+#endif
+#ifdef Q_OS_WIN32
+    mgr->setShellExtensionEnabled(mShellExtCheckBox->checkState() == Qt::Checked);
+#endif
+
+    updateProxySettings();
+
+#ifdef HAVE_SPARKLE_SUPPORT
+    if (AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
+        bool enabled = mCheckLatestVersionBox->checkState() == Qt::Checked;
+        AutoUpdateService::instance()->setAutoUpdateEnabled(enabled);
+    }
+#endif
+
+    bool language_changed = false;
+    if (mLanguageComboBox->currentIndex() != I18NHelper::getInstance()->preferredLanguage()) {
+        language_changed = true;
+        I18NHelper::getInstance()->setPreferredLanguage(mLanguageComboBox->currentIndex());
+    }
+
+    if (language_changed && seafApplet->yesOrNoBox(tr("You have changed languange. Restart to apply it?"), this, true))
+        seafApplet->restartApp();
+
+    // if (proxy_changed && seafApplet->yesOrNoBox(tr("You have changed proxy settings. Restart to apply it?"), this, true))
+    //     seafApplet->restartApp();
+
+}
+
+void SettingsDialog::closeEvent(QCloseEvent *event)
+{
+    // There is only one instance of settings dialog during the applet life
+    // time. During startup, applet loads settings from registry (or similar
+    // places on linux/osx) and load part of the settings from seaf daemon.
+    // Each time a user modifieds a settings item and clicks "OK" button, the
+    // change is both updated in memory and persisted to the registry.
+    event->ignore();
+    hide();
+}
+
+void SettingsDialog::showEvent(QShowEvent *event)
+{
+    SettingsManager *mgr = seafApplet->settingsManager();
+    // mgr->loadSettings();
+
+    Qt::CheckState state;
+    state = mgr->hideMainWindowWhenStarted() ? Qt::Checked : Qt::Unchecked;
+    mHideMainWinCheckBox->setCheckState(state);
+
+    state = mgr->allowInvalidWorktree() ? Qt::Checked : Qt::Unchecked;
+    mAllowInvalidWorktreeCheckBox->setCheckState(state);
+
+    state = mgr->syncExtraTempFile() ? Qt::Checked : Qt::Unchecked;
+    mSyncExtraTempFileCheckBox->setCheckState(state);
+
+    state = mgr->allowRepoNotFoundOnServer() ? Qt::Checked : Qt::Unchecked;
+    mAllowRepoNotFoundCheckBox->setCheckState(state);
+
+    state = mgr->httpSyncCertVerifyDisabled() ? Qt::Checked : Qt::Unchecked;
+    mDisableVerifyHttpSyncCert->setCheckState(state);
+
+    // currently supports windows only
+    state = mgr->autoStart() ? Qt::Checked : Qt::Unchecked;
+    mAutoStartCheckBox->setCheckState(state);
+#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC)
+    mAutoStartCheckBox->hide();
+#endif
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+    if (mgr->getFinderSyncExtensionAvailable()) {
+        mFinderSyncCheckBox->setEnabled(true);
+        state = mgr->getFinderSyncExtension() ? Qt::Checked : Qt::Unchecked;
+        mFinderSyncCheckBox->setCheckState(state);
+    } else {
+        mFinderSyncCheckBox->setEnabled(false);
+    }
+#else
+    mFinderSyncCheckBox->hide();
+#endif
+
+#if defined(Q_OS_WIN32)
+    state = mgr->shellExtensionEnabled() ? Qt::Checked : Qt::Unchecked;
+    mShellExtCheckBox->setCheckState(state);
+#else
+    mShellExtCheckBox->hide();
+#endif
+
+    // currently supports mac only
+    state = mgr->hideDockIcon() ? Qt::Checked : Qt::Unchecked;
+    mHideDockIconCheckBox->setCheckState(state);
+#if !defined(Q_OS_MAC)
+    mHideDockIconCheckBox->hide();
+#endif
+
+    state = mgr->notify() ? Qt::Checked : Qt::Unchecked;
+    mNotifyCheckBox->setCheckState(state);
+
+    int ratio;
+    ratio = mgr->maxDownloadRatio();
+    mDownloadSpinBox->setValue(ratio);
+    ratio = mgr->maxUploadRatio();
+    mUploadSpinBox->setValue(ratio);
+
+#ifdef HAVE_SPARKLE_SUPPORT
+    if (AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
+        state = AutoUpdateService::instance()->autoUpdateEnabled() ? Qt::Checked : Qt::Unchecked;
+        mCheckLatestVersionBox->setCheckState(state);
+    }
+#endif
+
+    mEnableSyncingWithExistingFolder->hide();
+
+    SettingsManager::SeafileProxy proxy = mgr->getProxy();
+    showHideControlsBasedOnCurrentProxyType(proxy.type);
+    mProxyMethodComboBox->setCurrentIndex(proxy.type);
+    mProxyHost->setText(proxy.host);
+    mProxyPort->setValue(proxy.port);
+    mProxyUsername->setText(proxy.username);
+    mProxyPassword->setText(proxy.password);
+    if (!proxy.username.isEmpty())
+        mProxyRequirePassword->setChecked(true);
+
+    mLanguageComboBox->setCurrentIndex(I18NHelper::getInstance()->preferredLanguage());
+
+    QDialog::showEvent(event);
+}
+
+
+void SettingsDialog::autoStartChanged(int state)
+{
+    qDebug("%s :%d", __func__, state);
+    bool autoStart = (mAutoStartCheckBox->checkState() == Qt::Checked);
+    seafApplet->settingsManager()->setAutoStart(autoStart);
+}
+
+void SettingsDialog::hideDockIconChanged(int state)
+{
+    qDebug("%s :%d", __func__, state);
+    bool hideDockIcon = (mHideDockIconCheckBox->checkState() == Qt::Checked);
+    seafApplet->settingsManager()->setHideDockIcon(hideDockIcon);
+}
+
+void SettingsDialog::notifyChanged(int state)
+{
+    qDebug("%s :%d", __func__, state);
+    bool notify = (mNotifyCheckBox->checkState() == Qt::Checked);
+    seafApplet->settingsManager()->setNotify(notify);
+}
+
+void SettingsDialog::downloadChanged(int value)
+{
+    qDebug("%s :%d", __func__, value);
+    seafApplet->settingsManager()->setMaxDownloadRatio(mDownloadSpinBox->value());
+}
+
+void SettingsDialog::uploadChanged(int value)
+{
+    qDebug("%s :%d", __func__, value);
+    seafApplet->settingsManager()->setMaxUploadRatio(mUploadSpinBox->value());
+}
+
+void SettingsDialog::proxyRequirePasswordChanged(int state)
+{
+    if (state == Qt::Checked) {
+        mProxyUsername->setEnabled(true);
+        mProxyUsernameLabel->setEnabled(true);
+        mProxyPassword->setEnabled(true);
+        mProxyPasswordLabel->setEnabled(true);
+    } else {
+        mProxyUsername->setEnabled(false);
+        mProxyUsernameLabel->setEnabled(false);
+        mProxyPassword->setEnabled(false);
+        mProxyPasswordLabel->setEnabled(false);
+    }
+}
+
+void SettingsDialog::showHideControlsBasedOnCurrentProxyType(int state)
+{
+    SettingsManager::ProxyType proxy_type =
+        static_cast<SettingsManager::ProxyType>(state);
+    switch(proxy_type) {
+        case SettingsManager::HttpProxy:
+            mProxyHost->setVisible(true);
+            mProxyHostLabel->setVisible(true);
+            mProxyPort->setVisible(true);
+            mProxyPortLabel->setVisible(true);
+            mProxyRequirePassword->setVisible(true);
+            mProxyUsername->setVisible(true);
+            mProxyUsernameLabel->setVisible(true);
+            mProxyPassword->setVisible(true);
+            mProxyPasswordLabel->setVisible(true);
+            break;
+        case SettingsManager::SocksProxy:
+            mProxyHost->setVisible(true);
+            mProxyHostLabel->setVisible(true);
+            mProxyPort->setVisible(true);
+            mProxyPortLabel->setVisible(true);
+            mProxyRequirePassword->setVisible(false);
+            mProxyUsername->setVisible(false);
+            mProxyUsernameLabel->setVisible(false);
+            mProxyPassword->setVisible(false);
+            mProxyPasswordLabel->setVisible(false);
+            break;
+        case SettingsManager::NoProxy:
+        case SettingsManager::SystemProxy:
+        default:
+            mProxyHost->setVisible(false);
+            mProxyHostLabel->setVisible(false);
+            mProxyPort->setVisible(false);
+            mProxyPortLabel->setVisible(false);
+            mProxyRequirePassword->setVisible(false);
+            mProxyUsername->setVisible(false);
+            mProxyUsernameLabel->setVisible(false);
+            mProxyPassword->setVisible(false);
+            mProxyPasswordLabel->setVisible(false);
+            break;
+    }
+
+    if (proxy_type == SettingsManager::HttpProxy ||
+        proxy_type == SettingsManager::SocksProxy) {
+        QString prefix =
+            proxy_type == SettingsManager::HttpProxy ? "http" : "socks";
+        QSettings settings;
+        QString key;
+        settings.beginGroup(kSettingsGroupForSettingsDialog);
+        if (mProxyHost->text().trimmed().isEmpty()) {
+            key = prefix + "_proxy_host";
+            if (settings.contains(key)) {
+                mProxyHost->setText(settings.value(key).toString());
+            }
+        }
+        if (mProxyPort->value() == 0) {
+            key = prefix + "_proxy_port";
+            if (settings.contains(key)) {
+                mProxyPort->setValue(settings.value(key).toInt());
+            }
+        }
+    }
+}
+
+// Called when the user clicked "OK" button of the settings dialog. Return
+// true if the proxy settings has been changed by the user.
+bool SettingsDialog::updateProxySettings()
+{
+    SettingsManager *mgr = seafApplet->settingsManager();
+    SettingsManager::SeafileProxy old_proxy = mgr->getProxy();
+
+    SettingsManager::ProxyType proxy_type = static_cast<SettingsManager::ProxyType>(mProxyMethodComboBox->currentIndex());
+    QString proxy_host = mProxyHost->text().trimmed();
+    QString proxy_username = mProxyUsername->text().trimmed();
+    QString proxy_password = mProxyPassword->text().trimmed();
+    int proxy_port = mProxyPort->value();
+
+    SettingsManager::SeafileProxy new_proxy(proxy_type);
+
+    switch(proxy_type) {
+        case SettingsManager::HttpProxy:
+            new_proxy.host = proxy_host;
+            new_proxy.port = proxy_port;
+            if (mProxyRequirePassword->checkState() == Qt::Checked) {
+                new_proxy.username = proxy_username;
+                new_proxy.password = proxy_password;
+                break;
+            }
+            break;
+        case SettingsManager::SocksProxy:
+            new_proxy.host = proxy_host;
+            new_proxy.port = proxy_port;
+            break;
+        case SettingsManager::NoProxy:
+        case SettingsManager::SystemProxy:
+        default:
+            break;
+    }
+
+    if (new_proxy != old_proxy) {
+        mgr->setProxy(new_proxy);
+        return true;
+    }
+
+    return false;
+}
+
+bool SettingsDialog::validateProxyInputs()
+{
+    SettingsManager::ProxyType proxy_type =
+        static_cast<SettingsManager::ProxyType>(
+            mProxyMethodComboBox->currentIndex());
+    if (proxy_type == SettingsManager::NoProxy ||
+        proxy_type == SettingsManager::SystemProxy) {
+        return true;
+    }
+
+    QString proxy_host = mProxyHost->text().trimmed();
+    if (proxy_host.isEmpty()) {
+        seafApplet->warningBox(tr("The proxy host address can't be empty"),
+                               this);
+        return false;
+    }
+
+    int proxy_port = mProxyPort->value();
+    if (proxy_port == 0) {
+        seafApplet->warningBox(tr("The proxy port is incorrect"),
+                               this);
+        return false;
+    }
+
+    if (mProxyRequirePassword->checkState() == Qt::Checked) {
+        QString proxy_username = mProxyUsername->text().trimmed();
+        QString proxy_password = mProxyPassword->text().trimmed();
+        if (proxy_username.isEmpty()) {
+            seafApplet->warningBox(tr("Proxy username can't be empty"), this);
+            return false;
+        } else if (proxy_password.isEmpty()) {
+            seafApplet->warningBox(tr("Proxy password can't be empty"), this);
+            return false;
+        }
+    }
+
+    QSettings settings;
+
+    settings.beginGroup(kSettingsGroupForSettingsDialog);
+    if (proxy_type == SettingsManager::HttpProxy) {
+        settings.setValue("http_proxy_host", proxy_host);
+        settings.setValue("http_proxy_port", proxy_port);
+    } else if (proxy_type == SettingsManager::SocksProxy) {
+        settings.setValue("socks_proxy_host", proxy_host);
+        settings.setValue("socks_proxy_port", proxy_port);
+    }
+    settings.endGroup();
+
+    return true;
+}
+
+void SettingsDialog::onOkBtnClicked()
+{
+    if (!validateProxyInputs()) {
+        return;
+    }
+    updateSettings();
+    accept();
+}
diff --git a/src/ui/settings-dialog.h b/src/ui/settings-dialog.h
new file mode 100644 (file)
index 0000000..799539f
--- /dev/null
@@ -0,0 +1,35 @@
+#include <QDialog>
+#include "ui_settings-dialog.h"
+
+#include <QUrl>
+#include <QString>
+
+
+class SettingsDialog : public QDialog,
+                    public Ui::SettingsDialog
+{
+    Q_OBJECT
+public:
+    SettingsDialog(QWidget *parent=0);
+
+private slots:
+
+    void autoStartChanged(int state);
+    void hideDockIconChanged(int state);
+    void notifyChanged(int state);
+    void downloadChanged(int value);
+    void uploadChanged(int value);
+    void closeEvent(QCloseEvent *event);
+    void showEvent(QShowEvent *event);
+    void updateSettings();
+    void onOkBtnClicked();
+
+    void proxyRequirePasswordChanged(int state);
+    void showHideControlsBasedOnCurrentProxyType(int state);
+
+private:
+    bool updateProxySettings();
+    bool validateProxyInputs();
+
+    Q_DISABLE_COPY(SettingsDialog);
+};
diff --git a/src/ui/ssl-confirm-dialog.cpp b/src/ui/ssl-confirm-dialog.cpp
new file mode 100644 (file)
index 0000000..03f649e
--- /dev/null
@@ -0,0 +1,43 @@
+#include "seafile-applet.h"
+#include "ssl-confirm-dialog.h"
+
+#include "utils/utils.h"
+
+SslConfirmDialog::SslConfirmDialog(const QUrl& url,
+                                   const QSslCertificate& cert,
+                                   const QSslCertificate& prev_cert,
+                                   QWidget *parent)
+    : QDialog(parent),
+      url_(url)
+{
+    setupUi(this);
+
+    setWindowTitle(tr("Untrusted Connection"));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+    setWindowIcon(QIcon(":/images/seafile.png"));
+
+    QString hint = tr("%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?").arg(url_.host());
+
+    QString fingerprint = dumpCertificateFingerprint(cert);
+    QString prev_fingerprint = dumpCertificateFingerprint(prev_cert);
+
+    hint += "\n\n";
+    hint += tr("Current RSA key fingerprint is %1").arg(fingerprint);
+    if (prev_fingerprint != "") {
+        hint += "\n";
+        hint += tr("Previous RSA key fingerprint is %1").arg(prev_fingerprint);
+    }
+
+    mHint->setText(hint);
+
+    adjustSize();
+
+    connect(mYesBtn, SIGNAL(clicked()), this, SLOT(accept()));
+    connect(mNoBtn, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+bool
+SslConfirmDialog::rememberChoice() const
+{
+    return mRememberChoiceCheckBox->checkState() == Qt::Checked;
+}
diff --git a/src/ui/ssl-confirm-dialog.h b/src/ui/ssl-confirm-dialog.h
new file mode 100644 (file)
index 0000000..7bda04b
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef SEAFILE_CLIENT_UI_SSL_CONFIRM_DIALOG_H
+#define SEAFILE_CLIENT_UI_SSL_CONFIRM_DIALOG_H
+
+#include <QUrl>
+
+#include <QDialog>
+#include "ui_ssl-confirm-dialog.h"
+
+class QSslCertificate;
+
+class SslConfirmDialog : public QDialog,
+                         public Ui::SslConfirmDialog
+{
+    Q_OBJECT
+public:
+    SslConfirmDialog(const QUrl& url,
+                     const QSslCertificate& cert,
+                     const QSslCertificate& prev_cert,
+                     QWidget *parent=0);
+
+    bool rememberChoice() const;
+
+private:
+    QUrl url_;
+};
+
+
+#endif // SEAFILE_CLIENT_UI_SSL_CONFIRM_DIALOG_H
diff --git a/src/ui/starred-file-item-delegate.cpp b/src/ui/starred-file-item-delegate.cpp
new file mode 100644 (file)
index 0000000..82ece97
--- /dev/null
@@ -0,0 +1,190 @@
+#include <QPainter>
+#include <QApplication>
+#include <QPixmap>
+
+#include "utils/utils.h"
+#include "utils/paint-utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "main-window.h"
+#include "rpc/rpc-client.h"
+#include "starred-files-list-model.h"
+#include "starred-file-item.h"
+#include "api/server-repo.h"
+
+#include "starred-file-item-delegate.h"
+
+namespace {
+
+/**
+            name
+   icon
+            subtitle
+ */
+
+const int kMarginLeft = 5;
+const int kMarginRight = 5;
+const int kMarginTop = 5;
+const int kMarginBottom = 5;
+const int kPadding = 5;
+
+const int kFileIconHeight = 36;
+const int kFileIconWidth = 36;
+const int kFileNameWidth = 210;
+const int kFileNameHeight = 30;
+
+const int kMarginBetweenFileIconAndName = 10;
+
+const char *kFileNameColor = "#3F3F3F";
+const char *kFileNameColorHighlighted = "#544D49";
+const char *kSubtitleColor = "#959595";
+const char *kSubtitleColorHighlighted = "#9D9B9A";
+const int kFileNameFontSize = 14;
+const int kSubtitleFontSize = 13;
+
+const char *kFileItemBackgroundColor = "white";
+const char *kFileItemBackgroundColorHighlighted = "#F9E0C7";
+
+const char *kItemBottomBorderColor = "#EEE";
+
+} // namespace
+
+StarredFileItemDelegate::StarredFileItemDelegate(QObject *parent)
+  : QStyledItemDelegate(parent)
+{
+}
+
+QSize StarredFileItemDelegate::sizeHint(const QStyleOptionViewItem &option,
+                                        const QModelIndex &index) const
+{
+    StarredFileItem *item = getItem(index);
+    if (!item) {
+        return QStyledItemDelegate::sizeHint(option, index);
+    }
+
+    return sizeHintForItem(option, item);
+}
+
+QSize StarredFileItemDelegate::sizeHintForItem(const QStyleOptionViewItem &option,
+                                               const StarredFileItem *item) const
+{
+    static const int width = kMarginLeft + kFileIconWidth
+        + kMarginBetweenFileIconAndName + kFileNameWidth
+        + kMarginRight + kPadding * 2;
+
+    static const int height = kFileIconHeight + kPadding * 2 + kMarginTop + kMarginBottom;
+
+    return QSize(width, height);
+}
+
+void StarredFileItemDelegate::paint(QPainter *painter,
+                                    const QStyleOptionViewItem& option,
+                                    const QModelIndex& index) const
+{
+    StarredFileItem *item = getItem(index);
+
+    paintItem(painter, option, item);
+}
+
+void StarredFileItemDelegate::paintItem(QPainter *painter,
+                                        const QStyleOptionViewItem& option,
+                                        const StarredFileItem *item) const
+{
+    QBrush backBrush;
+    bool selected = false;
+    const StarredItem& file = item->file();
+
+    if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) {
+        backBrush = QColor(kFileItemBackgroundColorHighlighted);
+        selected = true;
+
+    } else {
+        backBrush = QColor(kFileItemBackgroundColor);
+    }
+
+    painter->save();
+    painter->fillRect(option.rect, backBrush);
+    painter->restore();
+
+    // paint file icon
+    QPixmap icon;
+    switch (file.type) {
+    case StarredItem::REPO:
+        icon = QIcon(":/images/library-256.png").pixmap(36);
+        break;
+    case StarredItem::DIR:
+        icon = QIcon(":/images/files/file_folder.png").pixmap(36);
+        break;
+    default: // server version lower 7.0.0 will execute the statement
+        icon = getIconForFile(file.name());
+        break;
+    }
+
+    QPoint file_icon_pos(kMarginLeft + kPadding, kMarginTop + kPadding);
+    file_icon_pos += option.rect.topLeft();
+    painter->save();
+    painter->drawPixmap(file_icon_pos, icon);
+    painter->restore();
+
+    // Calculate the file column by the delta of mainwindow's width
+    const int file_name_width = kFileNameWidth
+      + seafApplet->mainWindow()->width() - seafApplet->mainWindow()->minimumWidth();
+
+    // Paint file name
+    painter->save();
+    QPoint file_name_pos = file_icon_pos + QPoint(kFileIconWidth + kMarginBetweenFileIconAndName, 0);
+    QRect file_name_rect(file_name_pos, QSize(file_name_width, kFileNameHeight));
+    painter->setPen(QColor(selected ? kFileNameColorHighlighted : kFileNameColor));
+    painter->setFont(changeFontSize(painter->font(), kFileNameFontSize));
+
+    painter->drawText(file_name_rect,
+                      Qt::AlignLeft | Qt::AlignTop,
+                      fitTextToWidth(file.name(), option.font, file_name_width),
+                      &file_name_rect);
+    painter->restore();
+
+    // Paint subtitle
+    QString subtitle, size, mtime;
+
+    size = readableFileSize(file.size);
+    mtime = translateCommitTime(file.mtime);
+
+    if (file.from_new_api) {
+        subtitle = mtime;
+    } else {
+        subtitle = size + "  " + mtime;
+    }
+
+    painter->save();
+    QPoint file_desc_pos = file_name_rect.bottomLeft() + QPoint(0, 5);
+    QRect file_desc_rect(file_desc_pos, QSize(file_name_width, kFileNameHeight));
+    painter->setFont(changeFontSize(painter->font(), kSubtitleFontSize));
+    painter->setPen(QColor(selected ? kSubtitleColorHighlighted : kSubtitleColor));
+    painter->drawText(file_desc_rect,
+                      Qt::AlignLeft | Qt::AlignTop,
+                      fitTextToWidth(subtitle, option.font, file_name_width),
+                      &file_desc_rect);
+    painter->restore();
+
+    // Draw the bottom border lines
+    painter->save();
+    painter->setPen(QPen(QColor(kItemBottomBorderColor), 1, Qt::SolidLine));
+    painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
+    painter->restore();
+}
+
+QPixmap StarredFileItemDelegate::getIconForFile(const QString& name) const
+{
+    return QIcon(::getIconByFileName(name)).pixmap(QSize(kFileIconWidth, kFileIconHeight));
+}
+
+StarredFileItem* StarredFileItemDelegate::getItem(const QModelIndex &index) const
+{
+    if (!index.isValid()) {
+        return NULL;
+    }
+
+    const StarredFilesListModel *model = (const StarredFilesListModel*)index.model();
+
+    return (StarredFileItem *)(model->itemFromIndex(index));
+}
diff --git a/src/ui/starred-file-item-delegate.h b/src/ui/starred-file-item-delegate.h
new file mode 100644 (file)
index 0000000..f6f1436
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
+#define SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
+
+#include <QStyledItemDelegate>
+#include <QPixmap>
+
+class QStandardItem;
+class QModelIndex;
+class QWidget;
+
+class StarredFileItem;
+
+class StarredFileItemDelegate : public QStyledItemDelegate {
+    Q_OBJECT
+public:
+    explicit StarredFileItemDelegate(QObject *parent=0);
+
+    void paint(QPainter *painter,
+               const QStyleOptionViewItem& option,
+               const QModelIndex& index) const;
+
+    QSize sizeHint(const QStyleOptionViewItem& option,
+                   const QModelIndex& index) const;
+
+
+private:
+    void paintItem(QPainter *painter,
+                   const QStyleOptionViewItem& opt,
+                   const StarredFileItem *item) const;
+
+    QSize sizeHintForItem(const QStyleOptionViewItem &option,
+                          const StarredFileItem *item) const;
+
+    StarredFileItem* getItem(const QModelIndex &index) const;
+
+    QPixmap getIconForFile(const QString& name) const;
+};
+
+
+#endif // SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
diff --git a/src/ui/starred-file-item.cpp b/src/ui/starred-file-item.cpp
new file mode 100644 (file)
index 0000000..e4e6e00
--- /dev/null
@@ -0,0 +1,8 @@
+
+#include "starred-file-item.h"
+
+StarredFileItem::StarredFileItem(const StarredItem& file)
+    : file_(file)
+{
+    setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+}
diff --git a/src/ui/starred-file-item.h b/src/ui/starred-file-item.h
new file mode 100644 (file)
index 0000000..a998442
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SEAFILE_CLIENT_STARRED_FILE_ITEM_H
+#define SEAFILE_CLIENT_STARRED_FILE_ITEM_H
+
+#include <QStandardItem>
+#include "api/starred-file.h"
+
+/**
+ * Represent a repo
+ */
+class StarredFileItem : public QStandardItem {
+public:
+    explicit StarredFileItem(const StarredItem& repo);
+
+    const StarredItem& file() const { return file_; }
+
+    /**
+     * Every time the item is painted, we record the metrics of each part of
+     * the item on the screen. So later we the mouse click/hover the item, we
+     * can decide which part is hovered, and to do corresponding actions.
+     */
+    struct Metrics {
+        QRect icon_rect;
+        QRect name_rect;
+        QRect subtitle_rect;
+        QRect status_icon_rect;
+    };
+
+    void setMetrics(const Metrics& metrics) const { metrics_ = metrics; }
+    const Metrics& metrics() const { return metrics_; }
+
+private:
+    StarredItem file_;
+
+    mutable Metrics metrics_;
+};
+
+#endif // SEAFILE_CLIENT_STARRED_FILE_ITEM_H
diff --git a/src/ui/starred-files-list-model.cpp b/src/ui/starred-files-list-model.cpp
new file mode 100644 (file)
index 0000000..a7cca33
--- /dev/null
@@ -0,0 +1,42 @@
+#include <QTimer>
+#include <QHash>
+#include <QDebug>
+#include <algorithm>            // std::sort
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "main-window.h"
+#include "rpc/rpc-client.h"
+#include "starred-file-item.h"
+
+#include "starred-files-list-model.h"
+
+namespace {
+
+bool compareFileByTimestamp(const StarredItem& a, const StarredItem& b)
+{
+    return a.mtime > b.mtime;
+}
+
+} // namespace
+
+StarredFilesListModel::StarredFilesListModel(QObject *parent)
+    : QStandardItemModel(parent)
+{
+}
+
+void StarredFilesListModel::setFiles(const std::vector<StarredItem>& files)
+{
+    int i, n = files.size();
+
+    clear();
+
+    std::vector<StarredItem> list = files;
+
+    std::sort(list.begin(), list.end(), compareFileByTimestamp);
+
+    for (i = 0; i < n; i++) {
+        StarredFileItem *item = new StarredFileItem(files[i]);
+        appendRow(item);
+    }
+}
diff --git a/src/ui/starred-files-list-model.h b/src/ui/starred-files-list-model.h
new file mode 100644 (file)
index 0000000..ba93fe1
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SEAFILE_CLIENT_STARRED_FILES_LIST_MODEL_H
+#define SEAFILE_CLIENT_STARRED_FILES_LIST_MODEL_H
+
+#include <vector>
+#include <QStandardItemModel>
+
+#include "api/starred-file.h"
+
+class QModelIndex;
+
+
+class StarredFilesListModel : public QStandardItemModel {
+    Q_OBJECT
+
+public:
+    StarredFilesListModel(QObject *parent=0);
+
+    void setFiles(const std::vector<StarredItem>& files);
+
+private:
+
+    std::vector<StarredItem> files_;
+};
+
+#endif // SEAFILE_CLIENT_STARRED_FILES_LIST_MODEL_H
diff --git a/src/ui/starred-files-list-view.cpp b/src/ui/starred-files-list-view.cpp
new file mode 100644 (file)
index 0000000..f45102e
--- /dev/null
@@ -0,0 +1,201 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#include <QUrlQuery>
+#else
+#include <QtGui>
+#endif
+#include <QHeaderView>
+#include <QDesktopServices>
+#include <QEvent>
+#include <QShowEvent>
+#include <QHideEvent>
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "repo-service.h"
+#include "starred-file-item.h"
+#include "starred-files-list-model.h"
+
+#include "starred-files-list-view.h"
+
+
+StarredFilesListView::StarredFilesListView(QWidget *parent)
+    : QListView(parent)
+{
+#if defined(Q_OS_MAC)
+    setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+
+    createActions();
+
+    connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+            this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+}
+
+void StarredFilesListView::createActions()
+{
+    open_file_action_ = new QAction(tr("&Open"), this);
+    open_file_action_->setIcon(QIcon(":/images/toolbar/file-gray.png"));
+    open_file_action_->setIconVisibleInMenu(true);
+    open_file_action_->setStatusTip(tr("Open this file"));
+    connect(open_file_action_, SIGNAL(triggered()), this, SLOT(openLocalFile()));
+
+    view_file_on_web_action_ = new QAction(tr("view on &Web"), this);
+    view_file_on_web_action_->setIcon(QIcon(":/images/cloud-gray.png"));
+    view_file_on_web_action_->setIconVisibleInMenu(true);
+    view_file_on_web_action_->setStatusTip(tr("view this file on website"));
+    connect(view_file_on_web_action_, SIGNAL(triggered()), this, SLOT(viewFileOnWeb()));
+}
+
+void StarredFilesListView::openLocalFile()
+{
+    StarredItem file = qvariant_cast<StarredItem>(view_file_on_web_action_->data());
+
+    if (!file.isFile()) {
+        openLocalDir(file);
+    } else {
+        openLocalFile(file);
+    }
+}
+
+void StarredFilesListView::viewFileOnWeb()
+{
+    StarredItem file = qvariant_cast<StarredItem>(view_file_on_web_action_->data());
+
+    const Account& account = seafApplet->accountManager()->currentAccount();
+    if (account.isValid()) {
+        QString strurl;
+        if (file.type == StarredItem::REPO) {
+            strurl = "library/" + file.repo_id + "/" + file.obj_name;
+        } else if (file.type == StarredItem::DIR) {
+            strurl = "library/" + file.repo_id + file.path;
+        } else {
+            strurl = "lib/" + file.repo_id + "/file" + file.path;
+        }
+        QUrl url = account.getAbsoluteUrl(strurl);
+        QDesktopServices::openUrl(url);
+    }
+}
+
+void StarredFilesListView::updateActions()
+{
+    StarredFileItem *item = NULL;
+    QItemSelection selected = selectionModel()->selection();
+    QModelIndexList indexes = selected.indexes();
+    if (indexes.size() != 0) {
+        const QModelIndex& index = indexes.at(0);
+        QStandardItem *it = ((StarredFilesListModel *)model())->itemFromIndex(index);
+        item = (StarredFileItem *)it;
+    }
+
+    if (!item) {
+        // No item is selected
+        open_file_action_->setEnabled(false);
+        view_file_on_web_action_->setEnabled(false);
+        return;
+    }
+
+    const StarredItem& file = item->file();
+
+    open_file_action_->setData(QVariant::fromValue(file));
+    view_file_on_web_action_->setData(QVariant::fromValue(file));
+}
+
+void StarredFilesListView::contextMenuEvent(QContextMenuEvent *event)
+{
+    QPoint pos = event->pos();
+    QModelIndex index = indexAt(pos);
+    if (!index.isValid()) {
+        return;
+    }
+
+    QStandardItem *item = getFileItem(index);
+    if (!item) {
+        return;
+    }
+    updateActions();
+    QMenu *menu = prepareContextMenu((StarredFileItem *)item);
+    pos = viewport()->mapToGlobal(pos);
+    menu->exec(pos);
+}
+
+QStandardItem*
+StarredFilesListView::getFileItem(const QModelIndex &index) const
+{
+    if (!index.isValid()) {
+        return NULL;
+    }
+    const StarredFilesListModel *model = (const StarredFilesListModel*)index.model();
+    QStandardItem *item = model->itemFromIndex(index);
+    return item;
+}
+
+QMenu* StarredFilesListView::prepareContextMenu(const StarredFileItem *item)
+{
+    QMenu *menu = new QMenu(this);
+
+    menu->addAction(open_file_action_);
+    menu->addAction(view_file_on_web_action_);
+
+    return menu;
+}
+
+bool StarredFilesListView::viewportEvent(QEvent *event)
+{
+    if (event->type() != QEvent::ToolTip && event->type() != QEvent::WhatsThis) {
+        return QListView::viewportEvent(event);
+    }
+
+    QPoint global_pos = QCursor::pos();
+    QPoint viewport_pos = viewport()->mapFromGlobal(global_pos);
+    QModelIndex index = indexAt(viewport_pos);
+    if (!index.isValid()) {
+        return true;
+    }
+
+    QStandardItem *qitem = getFileItem(index);
+    if (!qitem) {
+        return true;
+    }
+
+    StarredFileItem *item = (StarredFileItem *)qitem;
+
+    QRect item_rect = visualRect(index);
+
+    QString text = "<p style='white-space:pre'>";
+    text += item->file().name();
+    text += "</p>";
+
+    QToolTip::showText(QCursor::pos(), text, viewport(), item_rect);
+
+    return true;
+}
+
+void StarredFilesListView::onItemDoubleClicked(const QModelIndex& index)
+{
+    QStandardItem *item = getFileItem(index);
+    if (!item) {
+        return;
+    }
+
+    const StarredItem& file = ((StarredFileItem *)item)->file();
+
+    if (!file.isFile()) {
+        openLocalDir(file);
+    } else {
+        openLocalFile(file);
+    }
+}
+
+void StarredFilesListView::openLocalFile(const StarredItem& file)
+{
+    RepoService::instance()->openLocalFile(file.repo_id, file.path.mid(1), this);
+}
+
+void StarredFilesListView::openLocalDir(const StarredItem& file)
+{
+    RepoService::instance()->openFolder(file.repo_id, file.path.mid(1));
+}
diff --git a/src/ui/starred-files-list-view.h b/src/ui/starred-files-list-view.h
new file mode 100644 (file)
index 0000000..cdfdf15
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef SEAFILE_CLIENT_UI_STARRED_FILES_LIST_VIEW_H
+#define SEAFILE_CLIENT_UI_STARRED_FILES_LIST_VIEW_H
+
+#include <QListView>
+
+class QAction;
+class QContextMenuEvent;
+class QMenu;
+class QModelIndex;
+class QStandardItem;
+
+class StarredFileItem;
+class StarredItem;
+
+class StarredFilesListView : public QListView {
+    Q_OBJECT
+public:
+    StarredFilesListView(QWidget *parent=0);
+
+protected:
+    void contextMenuEvent(QContextMenuEvent *event);
+    bool viewportEvent(QEvent *event);
+
+private slots:
+    void onItemDoubleClicked(const QModelIndex& index);
+
+private slots:
+    void openLocalFile();
+    void viewFileOnWeb();
+
+private:
+    void createActions();
+    QMenu *prepareContextMenu(const StarredFileItem *item);
+    void updateActions();
+    QStandardItem* getFileItem(const QModelIndex &index) const;
+    void openLocalFile(const StarredItem& file);
+    void openLocalDir(const StarredItem& file);
+
+    QAction *open_file_action_;
+    QAction *view_file_on_web_action_;
+    QAction *open_repo_action_;
+    QAction *gen_share_link_action;
+};
+
+#endif // SEAFILE_CLIENT_UI_STARRED_FILES_LIST_VIEW_H
diff --git a/src/ui/starred-files-tab.cpp b/src/ui/starred-files-tab.cpp
new file mode 100644 (file)
index 0000000..ec99b29
--- /dev/null
@@ -0,0 +1,227 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QTimer>
+#include <QFileInfo>
+#include <QIcon>
+#include <QStackedWidget>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "api/requests.h"
+#include "api/starred-file.h"
+#include "loading-view.h"
+#include "logout-view.h"
+#include "starred-files-list-view.h"
+#include "starred-files-list-model.h"
+#include "starred-file-item-delegate.h"
+
+#include "starred-files-tab.h"
+
+namespace {
+
+const int kRefreshInterval = 1000 * 60 * 5; // 5 min
+const char *kLoadingFaieldLabelName = "loadingFailedText";
+const char *kEmptyViewLabelName = "emptyText";
+
+enum {
+    INDEX_LOADING_VIEW = 0,
+    INDEX_LOADING_FAILED_VIEW,
+    INDEX_EMPTY_VIEW,
+    INDEX_LOGOUT_VIEW,
+    INDEX_FILES_VIEW
+};
+
+}
+
+StarredFilesTab::StarredFilesTab(QWidget *parent)
+    : TabView(parent),
+      in_refresh_(false)
+{
+    createStarredFilesListView();
+    createLoadingView();
+    createLoadingFailedView();
+
+    //createLogoutView
+    logout_view_ = new LogoutView;
+    static_cast<LogoutView*>(logout_view_)->setQssStyleForTab();
+
+    createEmptyView();
+
+    mStack->insertWidget(INDEX_LOADING_VIEW, loading_view_);
+    mStack->insertWidget(INDEX_LOADING_FAILED_VIEW, loading_failed_view_);
+    mStack->insertWidget(INDEX_EMPTY_VIEW, empty_view_);
+    mStack->insertWidget(INDEX_LOGOUT_VIEW, logout_view_);
+    mStack->insertWidget(INDEX_FILES_VIEW, files_list_view_);
+
+    refresh_timer_ = new QTimer(this);
+    connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refresh()));
+
+    get_starred_files_req_ = NULL;
+    get_starred_items_req_ = NULL;
+
+    refresh();
+}
+
+void StarredFilesTab::createStarredFilesListView()
+{
+    files_list_view_ = new StarredFilesListView;
+    files_list_model_ = new StarredFilesListModel;
+
+    files_list_view_->setModel(files_list_model_);
+    files_list_view_->setItemDelegate(new StarredFileItemDelegate);
+}
+
+void StarredFilesTab::createLoadingView()
+{
+    loading_view_ = new LoadingView;
+    static_cast<LoadingView*>(loading_view_)->setQssStyleForTab();
+}
+
+void StarredFilesTab::createLoadingFailedView()
+{
+    loading_failed_view_ = new QWidget(this);
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    loading_failed_view_->setLayout(layout);
+
+    QLabel *label = new QLabel;
+    label->setObjectName(kLoadingFaieldLabelName);
+    QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("retry"));
+    QString label_text = tr("Failed to get starred files information<br/>"
+                            "Please %1").arg(link);
+    label->setText(label_text);
+    label->setAlignment(Qt::AlignCenter);
+
+    connect(label, SIGNAL(linkActivated(const QString&)),
+            this, SLOT(refresh()));
+
+    layout->addWidget(label);
+}
+
+void StarredFilesTab::createEmptyView()
+{
+    empty_view_ = new QWidget(this);
+    empty_view_->setObjectName("EmptyPlaceHolder");
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    empty_view_->setLayout(layout);
+
+    QLabel *label = new QLabel;
+    label->setObjectName(kEmptyViewLabelName);
+    QString label_text = tr("You have no starred files yet.");
+    label->setText(label_text);
+    label->setAlignment(Qt::AlignCenter);
+
+    layout->addWidget(label);
+}
+
+void StarredFilesTab::refresh()
+{
+    if (!seafApplet->accountManager()->hasAccount() ||
+        !seafApplet->accountManager()->accounts().front().isValid()) {
+        mStack->setCurrentIndex(INDEX_LOGOUT_VIEW);
+        return;
+    }
+    if (in_refresh_) {
+        return;
+    }
+
+    in_refresh_ = true;
+
+    showLoadingView();
+    //AccountManager *account_mgr = seafApplet->accountManager();
+
+    const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+    if (!seafApplet->accountManager()->hasAccount()) {
+        in_refresh_ = false;
+        return;
+    }
+
+    // server version 7.0.0 begin to support starred file dir repo
+    bool is_use_get_starred_item_api = seafApplet->accountManager()->currentAccount().isAtLeastVersion(7, 0, 0);
+
+    if (get_starred_files_req_) {
+        get_starred_files_req_->deleteLater();
+    }
+
+    if (get_starred_items_req_) {
+        get_starred_items_req_->deleteLater();
+    }
+
+    if (!is_use_get_starred_item_api) {
+        get_starred_files_req_ = new GetStarredFilesRequest(accounts[0]);
+        connect(get_starred_files_req_, SIGNAL(success(const std::vector<StarredItem>&)),
+                this, SLOT(refreshStarredFiles(const std::vector<StarredItem>&)));
+        connect(get_starred_files_req_, SIGNAL(failed(const ApiError&)),
+                this, SLOT(refreshStarredFilesFailed(const ApiError&)));
+        get_starred_files_req_->send();
+    } else {
+        get_starred_items_req_ = new GetStarredFilesRequestV2(accounts[0]);
+        connect(get_starred_items_req_, SIGNAL(success(const std::vector<StarredItem>&)),
+                this, SLOT(refreshStarredFilesV2(const std::vector<StarredItem>&)));
+        connect(get_starred_items_req_, SIGNAL(failed(const ApiError&)),
+                this, SLOT(refreshStarredFilesFailed(const ApiError&)));
+        get_starred_items_req_->send();
+    }
+
+}
+
+void StarredFilesTab::refreshStarredFiles(const std::vector<StarredItem>& files)
+{
+    in_refresh_ = false;
+
+    get_starred_files_req_->deleteLater();
+    get_starred_files_req_ = NULL;
+
+    files_list_model_->setFiles(files);
+    if (files.empty()) {
+        mStack->setCurrentIndex(INDEX_EMPTY_VIEW);
+    } else {
+        mStack->setCurrentIndex(INDEX_FILES_VIEW);
+    }
+}
+
+void StarredFilesTab::refreshStarredFilesV2(const std::vector<StarredItem>& files)
+{
+    in_refresh_ = false;
+
+    get_starred_items_req_->deleteLater();
+    get_starred_items_req_ = NULL;
+
+    files_list_model_->setFiles(files);
+    if (files.empty()) {
+        mStack->setCurrentIndex(INDEX_EMPTY_VIEW);
+    } else {
+        mStack->setCurrentIndex(INDEX_FILES_VIEW);
+    }
+}
+
+void StarredFilesTab::refreshStarredFilesFailed(const ApiError& error)
+{
+    qDebug("failed to refresh starred files");
+    in_refresh_ = false;
+
+    if (mStack->currentIndex() == INDEX_LOADING_VIEW) {
+        mStack->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+    }
+}
+
+void StarredFilesTab::showLoadingView()
+{
+    mStack->setCurrentIndex(INDEX_LOADING_VIEW);
+}
+
+void StarredFilesTab::startRefresh()
+{
+    refresh_timer_->start(kRefreshInterval);
+}
+
+void StarredFilesTab::stopRefresh()
+{
+    refresh_timer_->stop();
+}
diff --git a/src/ui/starred-files-tab.h b/src/ui/starred-files-tab.h
new file mode 100644 (file)
index 0000000..ef05c50
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef SEAFILE_CLIENT_UI_STARRED_FILES_TAB_H
+#define SEAFILE_CLIENT_UI_STARRED_FILES_TAB_H
+
+#include "tab-view.h"
+
+class QTimer;
+class QListWidget;
+
+class GetStarredFilesRequest;
+class GetStarredFilesRequestV2;
+class ApiError;
+class StarredItem;
+class StarredFilesListView;
+class StarredFilesListModel;
+
+/**
+ * The starred files tab
+ */
+class StarredFilesTab : public TabView {
+    Q_OBJECT
+public:
+    explicit StarredFilesTab(QWidget *parent=0);
+
+public slots:
+    void refresh();
+
+protected:
+    void startRefresh();
+    void stopRefresh();
+
+private slots:
+    void refreshStarredFiles(const std::vector<StarredItem>& files);
+    void refreshStarredFilesV2(const std::vector<StarredItem>& files);
+    void refreshStarredFilesFailed(const ApiError& error);
+
+private:
+    void createStarredFilesListView();
+    void createLoadingView();
+    void createLoadingFailedView();
+    void createEmptyView();
+    void showLoadingView();
+
+    QTimer *refresh_timer_;
+    bool in_refresh_;
+
+    StarredFilesListView *files_list_view_;
+    StarredFilesListModel *files_list_model_;
+
+    QWidget *loading_view_;
+    QWidget *loading_failed_view_;
+    QWidget *logout_view_;
+    QWidget *empty_view_;
+
+    GetStarredFilesRequest *get_starred_files_req_;
+    GetStarredFilesRequestV2 *get_starred_items_req_;
+};
+
+#endif // SEAFILE_CLIENT_UI_STARRED_FILES_TAB_H
diff --git a/src/ui/sync-errors-dialog.cpp b/src/ui/sync-errors-dialog.cpp
new file mode 100644 (file)
index 0000000..8ad0022
--- /dev/null
@@ -0,0 +1,371 @@
+#include <QtGlobal>
+
+#include <QtWidgets>
+#include <QTableView>
+#include <QResizeEvent>
+#include <QTimer>
+#include <QDesktopServices>
+#include <QCloseEvent>
+
+#include "QtAwesome.h"
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "rpc/sync-error.h"
+#include "rpc/local-repo.h"
+#include "sync-errors-dialog.h"
+
+namespace {
+
+const int kUpdateErrorsIntervalMSecs = 3000;
+
+const int kDefaultColumnWidth = 120;
+const int kDefaultColumnHeight = 40;
+
+const int kRepoNameColumnWidth = 100;
+const int kPathColumnWidth = 150;
+const int kErrorColumnWidth = 200;
+const int kTimestampColumnWidth = 80;
+const int kExtraPadding = 80;
+
+const int kDefaultColumnSum = kRepoNameColumnWidth + kPathColumnWidth + kErrorColumnWidth + kTimestampColumnWidth + kExtraPadding;
+
+enum {
+    INDEX_EMPTY_VIEW = 0,
+    INDEX_TABE_VIEW
+};
+
+enum {
+    COLUMN_REPO_NAME = 0,
+    COLUMN_PATH,
+    COLUMN_ERROR_STR,
+    COLUMN_TIMESTAMP,
+    MAX_COLUMN,
+};
+
+
+} // namespace
+
+// TODO: There are lots of common logic used in FileBrowserDialog and
+// SyncErrorsDialog. We should refactor out a base dialog class.
+SyncErrorsDialog::SyncErrorsDialog(QWidget *parent)
+    : QDialog(parent)
+{
+    // setupUi(this);
+
+    setWindowTitle(tr("File Sync Errors"));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+
+    Qt::WindowFlags flags =
+        (windowFlags() & ~Qt::WindowContextHelpButtonHint & ~Qt::Dialog) |
+        Qt::Window | Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint |
+        Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint |
+        Qt::WindowMaximizeButtonHint;
+
+    setWindowFlags(flags);
+
+    createEmptyView();
+
+    table_ = new SyncErrorsTableView;
+    model_ = new SyncErrorsTableModel(this);
+    table_->setModel(model_);
+
+    QWidget* widget = new QWidget;
+    widget->setObjectName("mainWidget");
+    QVBoxLayout* layout = new QVBoxLayout;
+    layout->setContentsMargins(0, 0, 0, 0);
+    layout->setSpacing(0);
+    setLayout(layout);
+    layout->addWidget(widget);
+
+    QVBoxLayout *vlayout = new QVBoxLayout;
+    vlayout->setContentsMargins(1, 0, 1, 0);
+    vlayout->setSpacing(0);
+    widget->setLayout(vlayout);
+
+    stack_ = new QStackedWidget;
+    stack_->insertWidget(INDEX_EMPTY_VIEW, empty_view_);
+    stack_->insertWidget(INDEX_TABE_VIEW, table_);
+    stack_->setContentsMargins(0, 0, 0, 0);
+
+    vlayout->addWidget(stack_);
+
+    onModelReset();
+    connect(model_, SIGNAL(modelReset()), this, SLOT(onModelReset()));
+}
+
+void SyncErrorsDialog::closeEvent(QCloseEvent *event)
+{
+    event->ignore();
+    this->hide();
+}
+
+void SyncErrorsDialog::updateErrors()
+{
+    model_->updateErrors();
+}
+
+void SyncErrorsDialog::onModelReset()
+{
+    if (model_->rowCount() == 0) {
+        stack_->setCurrentIndex(INDEX_EMPTY_VIEW);
+    } else {
+        stack_->setCurrentIndex(INDEX_TABE_VIEW);
+    }
+}
+
+
+void SyncErrorsDialog::createEmptyView()
+{
+    empty_view_ = new QWidget(this);
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    empty_view_->setLayout(layout);
+
+    QLabel *label = new QLabel;
+    label->setText(tr("No sync errors."));
+    label->setAlignment(Qt::AlignCenter);
+
+    layout->addWidget(label);
+}
+
+SyncErrorsTableView::SyncErrorsTableView(QWidget *parent)
+    : QTableView(parent)
+{
+    verticalHeader()->hide();
+    verticalHeader()->setDefaultSectionSize(36);
+    horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
+    horizontalHeader()->setStretchLastSection(true);
+    horizontalHeader()->setCascadingSectionResizes(true);
+    horizontalHeader()->setHighlightSections(false);
+    horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+
+    setGridStyle(Qt::NoPen);
+    setShowGrid(false);
+    setContentsMargins(0, 0, 0, 0);
+    setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+
+    setSelectionBehavior(QAbstractItemView::SelectRows);
+    setSelectionMode(QAbstractItemView::ExtendedSelection);
+    setMouseTracking(true);
+
+    createContextMenu();
+
+    connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+            this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+}
+
+void SyncErrorsTableView::contextMenuEvent(QContextMenuEvent *event)
+{
+    QPoint pos = event->pos();
+    int row = rowAt(pos.y());
+    qDebug("row = %d\n", row);
+    if (row == -1) {
+        return;
+    }
+
+    SyncErrorsTableModel *model = (SyncErrorsTableModel *)this->model();
+
+    SyncError error = model->errorAt(row);
+
+    prepareContextMenu(error);
+    pos = viewport()->mapToGlobal(pos);
+    context_menu_->exec(pos);
+}
+
+void SyncErrorsTableView::prepareContextMenu(const SyncError& error)
+{
+}
+
+void SyncErrorsTableView::createContextMenu()
+{
+    context_menu_ = new QMenu(this);
+}
+
+void SyncErrorsTableView::resizeEvent(QResizeEvent *event)
+{
+    QTableView::resizeEvent(event);
+    SyncErrorsTableModel *m = (SyncErrorsTableModel *)(model());
+    m->onResize(event->size());
+}
+
+void SyncErrorsTableView::onItemDoubleClicked(const QModelIndex& index)
+{
+    SyncErrorsTableModel *model = (SyncErrorsTableModel *)this->model();
+    SyncError error = model->errorAt(index.row());
+
+    // printf("error repo id is %s\n", error.repo_id.toUtf8().data());
+    if (!error.repo_id.isEmpty()) {
+        LocalRepo repo;
+        seafApplet->rpcClient()->getLocalRepo(error.repo_id, &repo);
+        if (repo.isValid()) {
+            QDesktopServices::openUrl(QUrl::fromLocalFile(repo.worktree));
+        }
+    }
+}
+
+SyncErrorsTableModel::SyncErrorsTableModel(QObject *parent)
+    : QAbstractTableModel(parent),
+      repo_name_column_width_(kRepoNameColumnWidth),
+      path_column_width_(kPathColumnWidth),
+      error_column_width_(kErrorColumnWidth)
+{
+    update_timer_ = new QTimer(this);
+    connect(update_timer_, SIGNAL(timeout()), this, SLOT(updateErrors()));
+    update_timer_->start(kUpdateErrorsIntervalMSecs);
+
+    updateErrors();
+}
+
+void SyncErrorsTableModel::updateErrors()
+{
+    std::vector<SyncError> errors;
+    bool success = seafApplet->rpcClient()->getSyncErrors(&errors, 0, 50);
+    if (!success) {
+        qDebug("failed to get sync errors");
+        return;
+    }
+
+    // SyncError fake_error;
+    // fake_error.repo_id = "xxx";
+    // fake_error.repo_name = "NotSoGood";
+    // fake_error.path = "/tmp/NotSoGood/BadFile";
+    // fake_error.error_id = 5;
+    // fake_error.timestamp = 1483056000;
+    // fake_error.translateErrorStr();
+    // errors.push_back(fake_error);
+
+    if (errors_ == errors) {
+        return;
+    }
+
+    if (errors_.size() != errors.size()) {
+        beginResetModel();
+        errors_ = errors;
+        endResetModel();
+        return;
+    }
+
+    for (int i = 0, n = errors.size(); i < n; i++) {
+        if (errors_[i] == errors[i]) {
+            continue;
+        }
+
+        errors_[i] = errors[i];
+        QModelIndex start = QModelIndex().child(i, 0);
+        QModelIndex stop = QModelIndex().child(i, MAX_COLUMN - 1);
+        emit dataChanged(start, stop);
+    }
+}
+
+int SyncErrorsTableModel::rowCount(const QModelIndex& parent) const
+{
+    return errors_.size();
+}
+
+int SyncErrorsTableModel::columnCount(const QModelIndex& parent) const
+{
+    return MAX_COLUMN;
+}
+
+void SyncErrorsTableModel::onResize(const QSize &size)
+{
+    int extra_width = size.width() - kDefaultColumnSum;
+    int extra_width_per_column = extra_width / 3;
+
+    repo_name_column_width_ = kRepoNameColumnWidth + extra_width_per_column;
+    path_column_width_ = kPathColumnWidth + extra_width_per_column;
+    error_column_width_ = kErrorColumnWidth + extra_width_per_column;
+
+    // name_column_width_ should be always larger than kPathColumnWidth
+    if (errors_.empty())
+        return;
+
+    // printf ("path_column_width_ = %d\n", path_column_width_);
+    emit dataChanged(
+        index(0, COLUMN_ERROR_STR),
+        index(errors_.size() - 1 , COLUMN_ERROR_STR));
+}
+
+QVariant SyncErrorsTableModel::data(const QModelIndex & index, int role) const
+{
+    if (!index.isValid()) {
+        return QVariant();
+    }
+
+    int column = index.column();
+
+    if (role == Qt::TextAlignmentRole)
+        return Qt::AlignLeft + Qt::AlignVCenter;
+
+    if (role == Qt::ToolTipRole)
+        return tr("Double click to open the library");
+
+    if (role == Qt::SizeHintRole) {
+        int h = kDefaultColumnHeight;
+        int w = kDefaultColumnWidth;
+        switch (column) {
+        case COLUMN_REPO_NAME:
+            w = repo_name_column_width_;
+            break;
+        case COLUMN_PATH:
+            w = path_column_width_;
+            break;
+        case COLUMN_ERROR_STR:
+            w = error_column_width_;
+            break;
+        case COLUMN_TIMESTAMP:
+            w = kTimestampColumnWidth;
+            break;
+        default:
+            break;
+        }
+        return QSize(w, h);
+    }
+
+    if (role != Qt::DisplayRole) {
+        return QVariant();
+    }
+
+    const SyncError &error = errors_[index.row()];
+
+    if (column == COLUMN_REPO_NAME) {
+        return error.repo_name;
+    } else if (column == COLUMN_PATH) {
+        return QDir::toNativeSeparators(error.path);
+    } else if (column == COLUMN_ERROR_STR) {
+        return error.error_str;
+    } else if (column == COLUMN_TIMESTAMP) {
+        return error.readable_time_stamp;
+    }
+
+    return QVariant();
+}
+
+QVariant SyncErrorsTableModel::headerData(int section,
+                                          Qt::Orientation orientation,
+                                          int role) const
+{
+    if (orientation == Qt::Vertical) {
+        return QVariant();
+    }
+
+    if (role == Qt::TextAlignmentRole)
+        return Qt::AlignLeft + Qt::AlignVCenter;
+
+    if (role != Qt::DisplayRole)
+        return QVariant();
+
+    if (section == COLUMN_REPO_NAME) {
+        return tr("Library");
+    } else if (section == COLUMN_PATH) {
+        return tr("Path");
+    } else if (section == COLUMN_ERROR_STR) {
+        return tr("Error");
+    } else if (section == COLUMN_TIMESTAMP) {
+        return tr("Time");
+    }
+
+
+    return QVariant();
+}
diff --git a/src/ui/sync-errors-dialog.h b/src/ui/sync-errors-dialog.h
new file mode 100644 (file)
index 0000000..f8b135a
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef SEAFILE_CLIENT_SYNC_ERRORS_DIALOG_H
+#define SEAFILE_CLIENT_SYNC_ERRORS_DIALOG_H
+
+#include <vector>
+
+#include <QTableView>
+#include <QHeaderView>
+#include <QAbstractTableModel>
+#include <QDialog>
+
+#include "rpc/sync-error.h"
+
+class QTimer;
+class QStackedWidget;
+class QSizeGrip;
+class QLabel;
+class QEvent;
+
+class SyncError;
+class SyncErrorsTableView;
+class SyncErrorsTableModel;
+
+class SyncErrorsDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    SyncErrorsDialog(QWidget *parent=0);
+    void updateErrors();
+
+    void closeEvent(QCloseEvent *event);
+
+private slots:
+    void onModelReset();
+
+private:
+    void createEmptyView();
+
+    QLabel *brand_label_;
+    QPushButton *minimize_button_;
+    QPushButton *close_button_;
+    QPoint old_pos_;
+
+    QSizeGrip *resizer_;
+
+    QStackedWidget *stack_;
+    SyncErrorsTableView *table_;
+    SyncErrorsTableModel *model_;
+    QWidget *empty_view_;
+};
+
+class SyncErrorsTableView : public QTableView
+{
+    Q_OBJECT
+
+public:
+    SyncErrorsTableView(QWidget *parent=0);
+
+    void contextMenuEvent(QContextMenuEvent *event);
+    void resizeEvent(QResizeEvent *event);
+
+private slots:
+    void onItemDoubleClicked(const QModelIndex& index);
+
+private:
+    void createContextMenu();
+    void prepareContextMenu(const SyncError& error);
+
+private:
+    QMenu *context_menu_;
+};
+
+
+class SyncErrorsTableModel : public QAbstractTableModel
+{
+    Q_OBJECT
+public:
+    SyncErrorsTableModel(QObject *parent=0);
+
+    int rowCount(const QModelIndex& parent=QModelIndex()) const;
+    int columnCount(const QModelIndex& parent=QModelIndex()) const;
+    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
+
+    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+    SyncError errorAt(size_t i) const { return (i >= errors_.size()) ? SyncError() : errors_[i]; }
+
+    void onResize(const QSize& size);
+
+public slots:
+    void updateErrors();
+
+private:
+
+    std::vector<SyncError> errors_;
+    QTimer *update_timer_;
+    int repo_name_column_width_;
+    int path_column_width_;
+    int error_column_width_;
+};
+
+#endif // SEAFILE_CLIENT_SYNC_ERRORS_DIALOG_H
diff --git a/src/ui/tab-view.cpp b/src/ui/tab-view.cpp
new file mode 100644 (file)
index 0000000..a426007
--- /dev/null
@@ -0,0 +1,30 @@
+#include <QStackedWidget>
+#include <QVBoxLayout>
+
+#include "tab-view.h"
+
+TabView::TabView(QWidget *parent)
+    : QWidget (parent)
+{
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->setContentsMargins(0, 0, 0, 0);
+    setLayout(layout);
+
+    mStack = new QStackedWidget;
+    layout->addWidget(mStack);
+}
+
+void TabView::showEvent(QShowEvent *event)
+{
+    startRefresh();
+    QWidget::showEvent(event);
+}
+
+/**
+ * Pause its freshing when this tab is not shown in front.
+ */
+void TabView::hideEvent(QHideEvent *event)
+{
+    stopRefresh();
+    QWidget::hideEvent(event);
+}
diff --git a/src/ui/tab-view.h b/src/ui/tab-view.h
new file mode 100644 (file)
index 0000000..e3fbb2b
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef SEAFILE_CLIENT_UI_TAB_VIEW_H
+#define SEAFILE_CLIENT_UI_TAB_VIEW_H
+
+#include <QWidget>
+
+class QStackedWidget;
+class QShowEvent;
+class QHideEvent;
+
+/**
+ * Represents one tab of a QTabWidget
+ */
+class TabView : public QWidget {
+    Q_OBJECT
+public:
+    TabView(QWidget *parent=0);
+    virtual ~TabView() {};
+
+public slots:
+    virtual void refresh() = 0;
+
+protected:
+    virtual void showEvent(QShowEvent *event);
+    virtual void hideEvent(QHideEvent *event);
+
+    virtual void startRefresh() = 0;
+    virtual void stopRefresh() = 0;
+
+    QStackedWidget *mStack;
+};
+
+#endif // SEAFILE_CLIENT_UI_TAB_VIEW_H
diff --git a/src/ui/tray-icon.cpp b/src/ui/tray-icon.cpp
new file mode 100644 (file)
index 0000000..4e4cb90
--- /dev/null
@@ -0,0 +1,733 @@
+#include <stdlib.h>
+
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QApplication>
+#include <QDesktopServices>
+#include <QSet>
+#include <QDebug>
+#include <QMenuBar>
+#include <QRunnable>
+#include <QSysInfo>
+#include <QCoreApplication>
+
+#include "rpc/local-repo.h"
+#include "utils/utils.h"
+#include "utils/utils-mac.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "rpc/rpc-client.h"
+#include "main-window.h"
+#include "settings-dialog.h"
+#include "settings-mgr.h"
+#include "server-status-service.h"
+#include "api/commit-details.h"
+#include "sync-errors-dialog.h"
+#include "account-mgr.h"
+#include "filebrowser/progress-dialog.h"
+
+#include "tray-icon.h"
+#if defined(Q_OS_MAC)
+#include "traynotificationmanager.h"
+// QT's platform apis
+// http://qt-project.org/doc/qt-4.8/exportedfunctions.html
+extern void qt_mac_set_dock_menu(QMenu *menu);
+#endif
+#include "utils/utils-mac.h"
+
+#if defined(Q_OS_LINUX)
+#include <QDBusConnection>
+#include <QDBusMessage>
+#include <QDBusPendingCall>
+#endif
+
+#include "src/ui/about-dialog.h"
+#if defined(Q_OS_WIN32)
+#include "utils/utils-win.h"
+#endif
+
+namespace {
+
+const int kRefreshInterval = 1000;
+const int kRotateTrayIconIntervalMilli = 250;
+const int kMessageDisplayTimeMSecs = 5000;
+#if defined(Q_OS_WIN32)
+const QString kShellExtFixExecutableName = "shellext-fix.exe";
+const QString kShellFixLogName = "shellext-fix.log";
+#endif
+#ifdef Q_OS_MAC
+void darkmodeWatcher(bool /*new Value*/) {
+    seafApplet->trayIcon()->reloadTrayIcon();
+}
+#endif
+
+QString folderToShow(const CommitDetails& details, const QString& worktree)
+{
+    QString path = worktree;
+    if (!details.added_files.empty()) {
+        path = pathJoin(worktree, details.added_files[0]);
+    } else if (!details.modified_files.empty()) {
+        path = pathJoin(worktree, details.modified_files[0]);
+    } else if (!details.added_dirs.empty()) {
+        path = pathJoin(worktree, details.added_dirs[0]);
+    } else if (!details.renamed_files.empty()) {
+        path = pathJoin(worktree, details.renamed_files[0].second);
+    } else if (!details.deleted_files.empty()) {
+        path = getParentPath(pathJoin(worktree, details.deleted_files[0]));
+    } else if (!details.deleted_dirs.empty()) {
+        path = getParentPath(pathJoin(worktree, details.deleted_dirs[0]));
+    }
+    return path;
+}
+
+// Read the commit diff from daemon rpc. We need to run it in a separate thread
+// since this may block for a while.
+class DiffReader : public QRunnable
+{
+public:
+    DiffReader(const LocalRepo &repo,
+               const QString &previous_commit_id,
+               const QString &commit_id)
+        : repo_(repo),
+          commit_id_(commit_id),
+          previous_commit_id_(previous_commit_id){};
+
+    void run()
+    {
+        CommitDetails details;
+        seafApplet->rpcClient()->getCommitDiff(
+            repo_.id, previous_commit_id_, commit_id_, &details);
+        showInGraphicalShell(folderToShow(details, repo_.worktree));
+    }
+
+private:
+    const LocalRepo repo_;
+    const QString commit_id_;
+    const QString previous_commit_id_;
+};
+
+} // namespace
+
+SeafileTrayIcon::SeafileTrayIcon(QObject *parent)
+    : QSystemTrayIcon(parent),
+      nth_trayicon_(0),
+      rotate_counter_(0),
+      state_(STATE_DAEMON_UP),
+      next_message_msec_(0),
+      sync_errors_dialog_(nullptr),
+      about_dialog_(nullptr),
+      log_dir_uploader_(nullptr)
+{
+    setState(STATE_DAEMON_DOWN);
+    rotate_timer_ = new QTimer(this);
+    connect(rotate_timer_, SIGNAL(timeout()), this, SLOT(rotateTrayIcon()));
+
+    refresh_timer_ = new QTimer(this);
+    connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refreshTrayIcon()));
+    connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refreshTrayIconToolTip()));
+#if defined(Q_OS_WIN32)
+    connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(checkTrayIconMessageQueue()));
+#endif
+
+    createActions();
+    createContextMenu();
+
+    connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
+            this, SLOT(onActivated(QSystemTrayIcon::ActivationReason)));
+
+#if !defined(Q_OS_LINUX)
+    connect(this, SIGNAL(messageClicked()),
+            this, SLOT(onMessageClicked()));
+#endif
+
+    hide();
+
+    createGlobalMenuBar();
+#if defined(Q_OS_MAC)
+    tnm = new TrayNotificationManager(this);
+#endif
+}
+
+void SeafileTrayIcon::start()
+{
+    show();
+    refresh_timer_->start(kRefreshInterval);
+#if defined(Q_OS_MAC)
+    utils::mac::set_darkmode_watcher(&darkmodeWatcher);
+#endif
+}
+
+void SeafileTrayIcon::createActions()
+{
+    disable_auto_sync_action_ = new QAction(tr("Disable auto sync"), this);
+    connect(disable_auto_sync_action_, SIGNAL(triggered()), this, SLOT(disableAutoSync()));
+
+    enable_auto_sync_action_ = new QAction(tr("Enable auto sync"), this);
+    connect(enable_auto_sync_action_, SIGNAL(triggered()), this, SLOT(enableAutoSync()));
+
+    quit_action_ = new QAction(tr("&Quit"), this);
+    connect(quit_action_, SIGNAL(triggered()), this, SLOT(quitSeafile()));
+
+    show_main_window_action_ = new QAction(tr("Show main window"), this);
+    connect(show_main_window_action_, SIGNAL(triggered()), this, SLOT(showMainWindow()));
+
+    settings_action_ = new QAction(tr("Settings"), this);
+    connect(settings_action_, SIGNAL(triggered()), this, SLOT(showSettingsWindow()));
+
+    open_seafile_folder_action_ = new QAction(tr("Open %1 &folder").arg(getBrand()), this);
+    open_seafile_folder_action_->setStatusTip(tr("open %1 folder").arg(getBrand()));
+    connect(open_seafile_folder_action_, SIGNAL(triggered()), this, SLOT(openSeafileFolder()));
+
+#if defined(Q_OS_WIN32)
+    shellext_fix_action_ = new QAction(tr("Repair explorer extension"), this);
+    connect(shellext_fix_action_, SIGNAL(triggered()), this, SLOT(shellExtFix()));
+#endif
+    open_log_directory_action_ = new QAction(tr("Open &logs folder"), this);
+    open_log_directory_action_->setStatusTip(tr("open %1 log folder").arg(getBrand()));
+    connect(open_log_directory_action_, SIGNAL(triggered()), this, SLOT(openLogDirectory()));
+
+    upload_log_directory_action_ = new QAction(tr("Upload log files"), this);
+    upload_log_directory_action_->setStatusTip(tr("upload %1 log files").arg(getBrand()));
+    connect(upload_log_directory_action_, SIGNAL(triggered()), this, SLOT(uploadLogDirectory()));
+
+    show_sync_errors_action_ = new QAction(tr("Show file sync errors"), this);
+    show_sync_errors_action_->setStatusTip(tr("Show file sync errors"));
+    connect(show_sync_errors_action_, SIGNAL(triggered()), this, SLOT(showSyncErrorsDialog()));
+
+    about_action_ = new QAction(tr("&About"), this);
+    about_action_->setStatusTip(tr("Show the application's About box"));
+    connect(about_action_, SIGNAL(triggered()), this, SLOT(about()));
+
+    open_help_action_ = new QAction(tr("&Online help"), this);
+    open_help_action_->setStatusTip(tr("open %1 online help").arg(getBrand()));
+    connect(open_help_action_, SIGNAL(triggered()), this, SLOT(openHelp()));
+}
+
+void SeafileTrayIcon::createContextMenu()
+{
+    // help_menu_ = new QMenu(tr("Help"), NULL);
+    // help_menu_->addAction(about_action_);
+    // help_menu_->addAction(open_help_action_);
+
+    context_menu_ = new QMenu(NULL);
+    context_menu_->addAction(show_main_window_action_);
+    context_menu_->addAction(open_seafile_folder_action_);
+    context_menu_->addAction(settings_action_);
+    context_menu_->addSeparator();
+    context_menu_->addAction(open_log_directory_action_);
+ #if defined(Q_OS_WIN32)
+    context_menu_->addAction(shellext_fix_action_);
+ #endif
+    context_menu_->addSeparator();
+    //context_menu_->addAction(upload_log_directory_action_);
+    context_menu_->addAction(show_sync_errors_action_);
+    // context_menu_->addMenu(help_menu_);
+    context_menu_->addSeparator();
+    context_menu_->addAction(about_action_);
+    context_menu_->addAction(open_help_action_);
+    context_menu_->addSeparator();
+    context_menu_->addAction(enable_auto_sync_action_);
+    context_menu_->addAction(disable_auto_sync_action_);
+    context_menu_->addSeparator();
+    context_menu_->addAction(quit_action_);
+
+    setContextMenu(context_menu_);
+    connect(context_menu_, SIGNAL(aboutToShow()), this, SLOT(prepareContextMenu()));
+}
+
+void SeafileTrayIcon::prepareContextMenu()
+{
+    if (seafApplet->settingsManager()->autoSync()) {
+        enable_auto_sync_action_->setVisible(false);
+        disable_auto_sync_action_->setVisible(true);
+    } else {
+        enable_auto_sync_action_->setVisible(true);
+        disable_auto_sync_action_->setVisible(false);
+    }
+
+    std::vector<SyncError> errors;
+    bool success = seafApplet->rpcClient()->getSyncErrors(&errors, 0, 1);
+    if (!success) {
+        qDebug("failed to get sync errors");
+        return;
+    }
+
+    if (errors.empty()) {
+        show_sync_errors_action_->setEnabled(false);
+    } else {
+        show_sync_errors_action_->setEnabled(true);
+    }
+}
+
+void SeafileTrayIcon::createGlobalMenuBar()
+{
+    // support it only on mac os x currently
+    // TODO: destroy the objects when seafile closes
+#ifdef Q_OS_MAC
+    // create qmenu used in menubar and docker menu
+    global_menu_ = new QMenu(tr("File"));
+    global_menu_->addAction(show_main_window_action_);
+    global_menu_->addAction(open_seafile_folder_action_);
+    global_menu_->addAction(settings_action_);
+    global_menu_->addAction(open_log_directory_action_);
+    //global_menu_->addAction(upload_log_directory_action_);
+    global_menu_->addAction(show_sync_errors_action_);
+    global_menu_->addSeparator();
+    global_menu_->addAction(enable_auto_sync_action_);
+    global_menu_->addAction(disable_auto_sync_action_);
+
+    global_menubar_ = new QMenuBar(0);
+    global_menubar_->addMenu(global_menu_);
+    // TODO fix the line below which crashes under qt5.4.0
+    //global_menubar_->addMenu(help_menu_);
+    global_menubar_->setNativeMenuBar(true);
+    qApp->setAttribute(Qt::AA_DontUseNativeMenuBar, false);
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
+    global_menu_->setAsDockMenu(); // available after qt5.2.0
+#else
+    qt_mac_set_dock_menu(global_menu_); // deprecated in latest qt
+#endif
+    // create QMenuBar that has no parent, so we can share the global menubar
+#endif // Q_OS_MAC
+}
+
+void SeafileTrayIcon::rotate(bool start)
+{
+    /* tray icon should not be refreshed on Gnome according to their guidelines */
+#if defined(Q_OS_LINUX)
+    const char *env = g_getenv("DESKTOP_SESSION");
+    if (env != NULL &&
+        (strcmp(env, "gnome") == 0 || strcmp(env, "gnome-wayland") == 0)) {
+        return;
+    }
+#endif
+
+    if (start) {
+        rotate_counter_ = 0;
+        if (!rotate_timer_->isActive()) {
+            nth_trayicon_ = 0;
+            rotate_timer_->start(kRotateTrayIconIntervalMilli);
+        }
+    } else {
+        rotate_timer_->stop();
+    }
+}
+
+void SeafileTrayIcon::showMessage(const QString &title,
+                                  const QString &message,
+                                  const QString &repo_id,
+                                  const QString &commit_id,
+                                  const QString &previous_commit_id,
+                                  MessageIcon icon,
+                                  int millisecondsTimeoutHint)
+{
+#ifdef Q_OS_MAC
+    repo_id_ = repo_id;
+    commit_id_ = commit_id;
+    previous_commit_id_ = previous_commit_id;
+    if (QSysInfo::MacintoshVersion < QSysInfo::MV_MOUNTAINLION) {
+        // qWarning("using old style notifications");
+        QIcon info_icon(":/images/info.png");
+        TrayNotificationWidget* trayNotification = new TrayNotificationWidget(info_icon.pixmap(32, 32), title, message);
+        tnm->append(trayNotification);
+        return;
+    }
+    // qWarning("using new style notifications");
+
+    QSystemTrayIcon::showMessage(title, message, icon, millisecondsTimeoutHint);
+#elif defined(Q_OS_LINUX)
+    repo_id_ = repo_id;
+    Q_UNUSED(icon);
+    QVariantMap hints;
+    QString brand = getBrand();
+    hints["resident"] = QVariant(true);
+    hints["desktop-entry"] = QVariant(brand);
+    QList<QVariant> args = QList<QVariant>() << brand << quint32(0) << brand
+                                             << title << message << QStringList () << hints << qint32(-1);
+    QDBusMessage method = QDBusMessage::createMethodCall("org.freedesktop.Notifications","/org/freedesktop/Notifications", "org.freedesktop.Notifications", "Notify");
+    method.setArguments(args);
+    QDBusConnection::sessionBus().asyncCall(method);
+#else
+    TrayMessage msg;
+    msg.title = title;
+    msg.message = message;
+    msg.icon = icon;
+    msg.repo_id = repo_id;
+    msg.commit_id = commit_id;
+    msg.previous_commit_id = previous_commit_id;
+    pending_messages_.enqueue(msg);
+#endif
+}
+
+void SeafileTrayIcon::rotateTrayIcon()
+{
+    if (rotate_counter_ >= 8 || !seafApplet->settingsManager()->autoSync()) {
+        rotate_timer_->stop();
+        if (!seafApplet->settingsManager()->autoSync())
+            setState (STATE_DAEMON_AUTOSYNC_DISABLED);
+        else
+            setState (STATE_DAEMON_UP);
+        return;
+    }
+
+    TrayState states[] = { STATE_TRANSFER_1, STATE_TRANSFER_2 };
+    int index = nth_trayicon_ % 2;
+    setIcon(stateToIcon(states[index]));
+
+    nth_trayicon_++;
+    rotate_counter_++;
+}
+
+void SeafileTrayIcon::setState(TrayState state, const QString& tip)
+{
+    if (state_ == state) {
+        return;
+    }
+
+    QString tool_tip = tip.isEmpty() ? getBrand() : tip;
+
+    setIcon(stateToIcon(state));
+    setToolTip(tool_tip);
+}
+
+void SeafileTrayIcon::reloadTrayIcon()
+{
+    setIcon(stateToIcon(state_));
+
+#if defined(Q_OS_LINUX)
+    hide();
+    show();
+#endif
+}
+
+QIcon SeafileTrayIcon::getIcon(const QString& name)
+{
+    if (icon_cache_.contains(name)) {
+        return icon_cache_[name];
+    }
+
+    QIcon icon(name);
+    icon_cache_[name] = icon;
+    return icon;
+}
+
+QIcon SeafileTrayIcon::stateToIcon(TrayState state)
+{
+    state_ = state;
+#if defined(Q_OS_WIN32)
+    QString icon_name;
+    switch (state) {
+    case STATE_DAEMON_UP:
+        icon_name = ":/images/win/daemon_up.ico";
+        break;
+    case STATE_DAEMON_DOWN:
+        icon_name = ":/images/win/daemon_down.ico";
+        break;
+    case STATE_DAEMON_AUTOSYNC_DISABLED:
+        icon_name = ":/images/win/seafile_auto_sync_disabled.ico";
+        break;
+    case STATE_TRANSFER_1:
+        icon_name = ":/images/win/seafile_transfer_1.ico";
+        break;
+    case STATE_TRANSFER_2:
+        icon_name = ":/images/win/seafile_transfer_2.ico";
+        break;
+    case STATE_SERVERS_NOT_CONNECTED:
+        icon_name = ":/images/win/seafile_warning.ico";
+        break;
+    case STATE_HAVE_UNREAD_MESSAGE:
+        icon_name = ":/images/win/notification.ico";
+        break;
+    }
+    return getIcon(icon_name);
+#elif defined(Q_OS_MAC)
+    bool isDarkMode = utils::mac::is_darkmode();
+    // filename = icon_name + ?white + .png
+    QString icon_name;
+
+    switch (state) {
+    case STATE_DAEMON_UP:
+        icon_name = ":/images/mac/daemon_up";
+        break;
+    case STATE_DAEMON_DOWN:
+        icon_name = ":/images/mac/daemon_down.png";
+        break;
+    case STATE_DAEMON_AUTOSYNC_DISABLED:
+        icon_name = ":/images/mac/seafile_auto_sync_disabled";
+        break;
+    case STATE_TRANSFER_1:
+        icon_name = ":/images/mac/seafile_transfer_1";
+        break;
+    case STATE_TRANSFER_2:
+        icon_name = ":/images/mac/seafile_transfer_2";
+        break;
+    case STATE_SERVERS_NOT_CONNECTED:
+        icon_name = ":/images/mac/seafile_warning";
+        break;
+    case STATE_HAVE_UNREAD_MESSAGE:
+        icon_name = ":/images/mac/notification";
+        break;
+    }
+    return getIcon(icon_name + (isDarkMode ? "_white" : "") + ".png");
+#else
+    QString icon_name;
+    switch (state) {
+    case STATE_DAEMON_UP:
+        icon_name = ":/images/daemon_up.png";
+        break;
+    case STATE_DAEMON_DOWN:
+        icon_name = ":/images/daemon_down.png";
+        break;
+    case STATE_DAEMON_AUTOSYNC_DISABLED:
+        icon_name = ":/images/seafile_auto_sync_disabled.png";
+        break;
+    case STATE_TRANSFER_1:
+        icon_name = ":/images/seafile_transfer_1.png";
+        break;
+    case STATE_TRANSFER_2:
+        icon_name = ":/images/seafile_transfer_2.png";
+        break;
+    case STATE_SERVERS_NOT_CONNECTED:
+        icon_name = ":/images/seafile_warning.png";
+        break;
+    case STATE_HAVE_UNREAD_MESSAGE:
+        icon_name = ":/images/notification.png";
+        break;
+    }
+    return getIcon(icon_name);
+#endif
+}
+
+void SeafileTrayIcon::showMainWindow()
+{
+    MainWindow *main_win = seafApplet->mainWindow();
+    main_win->showWindow();
+}
+
+void SeafileTrayIcon::about()
+{
+    if (!about_dialog_) {
+        about_dialog_ = new AboutDialog();
+    }
+    about_dialog_->show();
+    about_dialog_->raise();
+    about_dialog_->activateWindow();
+    return;
+
+//     QMessageBox::about(seafApplet->mainWindow(), tr("About %1").arg(getBrand()),
+//                        tr("<h2>%1 Client %2</h2>").arg(getBrand()).arg(
+//                            STRINGIZE(SEAFILE_CLIENT_VERSION))
+// #if defined(SEAFILE_CLIENT_REVISION)
+//                        .append("<h4> REV %1 </h4>")
+//                        .arg(STRINGIZE(SEAFILE_CLIENT_REVISION))
+// #endif
+//                        );
+}
+
+void SeafileTrayIcon::openHelp()
+{
+    QString url;
+    if (QLocale::system().name() == "zh_CN") {
+        url = "https://www.seafile.com/help/install/";
+    } else {
+        url = "https://www.seafile.com/en/help/install/";
+    }
+
+    QDesktopServices::openUrl(QUrl(url));
+}
+
+void SeafileTrayIcon::openSeafileFolder()
+{
+    QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(seafApplet->configurator()->seafileDir()).path()));
+}
+
+void SeafileTrayIcon::shellExtFix()
+{
+#if defined(Q_OS_WIN32)
+    QString application_dir = QCoreApplication::applicationDirPath();
+    QString shellext_fix_path = pathJoin(application_dir, kShellExtFixExecutableName);
+    shellext_fix_path = QString("\"%1\"").arg(shellext_fix_path);
+
+    QString log_dir = QDir(seafApplet->configurator()->ccnetDir()).absoluteFilePath("logs");
+    QString log_path = pathJoin(log_dir, kShellFixLogName);
+
+    qWarning("will exec shellext fix command is: %s, the log path is: %s",
+        toCStr(shellext_fix_path),
+        toCStr(log_path));
+
+    DWORD res = utils::win::runShellAsAdministrator(toCStr(shellext_fix_path), toCStr(log_path), SW_HIDE);
+    if (res == 0) {
+        seafApplet->warningBox(tr("Successfully fixed sync status icons for Explorer"));
+
+    } else {
+        seafApplet->warningBox(tr("Faild to fix sync status icons for Explorer"));
+        qWarning("faild to fix sync status icons for explorer");
+    }
+
+#endif
+}
+
+void SeafileTrayIcon::openLogDirectory()
+{
+    QString log_path = QDir(seafApplet->configurator()->ccnetDir()).absoluteFilePath("logs");
+    QDesktopServices::openUrl(QUrl::fromLocalFile(log_path));
+}
+
+void SeafileTrayIcon::uploadLogDirectory()
+{
+    if (!seafApplet->accountManager()->currentAccount().isValid()) {
+        seafApplet->warningBox(tr("Please login first"));
+        return;
+    }
+
+    if (log_dir_uploader_ == nullptr) {
+        log_dir_uploader_ = new LogDirUploader();
+        connect(log_dir_uploader_, SIGNAL(finished()), this, SLOT(clearUploader()));
+        log_dir_uploader_->start();
+    }
+}
+
+void SeafileTrayIcon::clearUploader()
+{
+    log_dir_uploader_ = nullptr;
+}
+
+void SeafileTrayIcon::showSettingsWindow()
+{
+    seafApplet->settingsDialog()->show();
+    seafApplet->settingsDialog()->raise();
+    seafApplet->settingsDialog()->activateWindow();
+}
+
+void SeafileTrayIcon::onActivated(QSystemTrayIcon::ActivationReason reason)
+{
+#if !defined(Q_OS_MAC)
+    switch(reason) {
+    case QSystemTrayIcon::Trigger: // single click
+    case QSystemTrayIcon::MiddleClick:
+    case QSystemTrayIcon::DoubleClick:
+        showMainWindow();
+        break;
+    default:
+        return;
+    }
+#endif
+}
+
+void SeafileTrayIcon::disableAutoSync()
+{
+    seafApplet->settingsManager()->setAutoSync(false);
+}
+
+void SeafileTrayIcon::enableAutoSync()
+{
+    seafApplet->settingsManager()->setAutoSync(true);
+}
+
+void SeafileTrayIcon::quitSeafile()
+{
+    QCoreApplication::exit(0);
+}
+
+void SeafileTrayIcon::refreshTrayIcon()
+{
+    if (rotate_timer_->isActive()) {
+        return;
+    }
+
+    if (!seafApplet->settingsManager()->autoSync()) {
+        setState(STATE_DAEMON_AUTOSYNC_DISABLED,
+                 tr("auto sync is disabled"));
+        return;
+    }
+
+    if (!ServerStatusService::instance()->allServersConnected()) {
+        setState(STATE_SERVERS_NOT_CONNECTED, tr("some servers not connected"));
+        return;
+    }
+
+    setState(STATE_DAEMON_UP);
+}
+
+void SeafileTrayIcon::refreshTrayIconToolTip()
+{
+    if (!seafApplet->settingsManager()->autoSync())
+        return;
+
+    int up_rate, down_rate;
+    if (seafApplet->rpcClient()->getUploadRate(&up_rate) < 0 ||
+        seafApplet->rpcClient()->getDownloadRate(&down_rate) < 0) {
+        return;
+    }
+
+    if (up_rate <= 0 && down_rate <= 0) {
+        return;
+    }
+
+    QString uploadStr = tr("Uploading");
+    QString downloadStr =  tr("Downloading");
+    if (up_rate > 0 && down_rate > 0) {
+        setToolTip(QString("%1 %2/s, %3 %4/s\n").
+                   arg(uploadStr).arg(readableFileSize(up_rate)).
+                   arg(downloadStr).arg(readableFileSize(down_rate)));
+    } else if (up_rate > 0) {
+        setToolTip(QString("%1 %2/s\n").
+                   arg(uploadStr).arg(readableFileSize(up_rate)));
+    } else /* down_rate > 0*/ {
+        setToolTip(QString("%1 %2/s\n").
+                   arg(downloadStr).arg(readableFileSize(down_rate)));
+    }
+
+    rotate(true);
+}
+
+void SeafileTrayIcon::onMessageClicked()
+{
+    if (repo_id_.isEmpty())
+        return;
+    LocalRepo repo;
+    if (seafApplet->rpcClient()->getLocalRepo(repo_id_, &repo) != 0 ||
+        !repo.isValid() || repo.worktree_invalid)
+        return;
+
+    DiffReader *reader = new DiffReader(repo, previous_commit_id_, commit_id_);
+    QThreadPool::globalInstance()->start(reader);
+}
+
+void SeafileTrayIcon::checkTrayIconMessageQueue()
+{
+    if (pending_messages_.empty()) {
+        return;
+    }
+
+    qint64 now = QDateTime::currentMSecsSinceEpoch();
+    if (now < next_message_msec_) {
+        return;
+    }
+
+    TrayMessage msg = pending_messages_.dequeue();
+    QSystemTrayIcon::showMessage(msg.title, msg.message, msg.icon, kMessageDisplayTimeMSecs);
+    repo_id_ = msg.repo_id;
+    commit_id_ = msg.commit_id;
+    next_message_msec_ = now + kMessageDisplayTimeMSecs;
+}
+
+
+void SeafileTrayIcon::showSyncErrorsDialog()
+{
+    if (sync_errors_dialog_ == nullptr) {
+        sync_errors_dialog_ = new SyncErrorsDialog;
+    }
+
+    sync_errors_dialog_->updateErrors();
+    sync_errors_dialog_->show();
+    sync_errors_dialog_->raise();
+    sync_errors_dialog_->activateWindow();
+}
diff --git a/src/ui/tray-icon.h b/src/ui/tray-icon.h
new file mode 100644 (file)
index 0000000..10200c5
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef SEAFILE_CLIENT_TRAY_ICON_H
+#define SEAFILE_CLIENT_TRAY_ICON_H
+
+#include <QSystemTrayIcon>
+#include <QHash>
+#include <QQueue>
+
+#include "account.h"
+#include "log-uploader.h"
+
+class ApiError;
+class QAction;
+class QMenu;
+class QMenuBar;
+#if defined(Q_OS_MAC)
+class TrayNotificationManager;
+#endif
+class AboutDialog;
+class SyncErrorsDialog;
+class SeafileTrayIcon : public QSystemTrayIcon {
+    Q_OBJECT
+
+public:
+    explicit SeafileTrayIcon(QObject *parent=0);
+
+    enum TrayState {
+        STATE_DAEMON_UP = 0,
+        STATE_DAEMON_DOWN,
+        STATE_DAEMON_AUTOSYNC_DISABLED,
+        STATE_TRANSFER_1,
+        STATE_TRANSFER_2,
+        STATE_SERVERS_NOT_CONNECTED,
+        STATE_HAVE_UNREAD_MESSAGE,
+    };
+
+    void start();
+
+    TrayState state() const { return state_; }
+    void setState(TrayState state, const QString& tip=QString());
+    void rotate(bool start);
+
+    void reloadTrayIcon();
+
+    void showMessage(const QString& title,
+                     const QString& message,
+                     const QString& repo_id = QString(),
+                     const QString& commit_id = QString(),
+                     const QString& previous_commit_id = QString(),
+                     MessageIcon icon = Information,
+                     int millisecondsTimeoutHint = 10000);
+
+public slots:
+    void showSettingsWindow();
+
+private slots:
+    void disableAutoSync();
+    void enableAutoSync();
+    void quitSeafile();
+    void onActivated(QSystemTrayIcon::ActivationReason);
+    void prepareContextMenu();
+    void showMainWindow();
+    void rotateTrayIcon();
+    void refreshTrayIcon();
+    void refreshTrayIconToolTip();
+    void openHelp();
+    void openSeafileFolder();
+    void openLogDirectory();
+    void shellExtFix();
+    void uploadLogDirectory();
+    void about();
+    void checkTrayIconMessageQueue();
+    void clearUploader();
+
+    // only used on windows
+    void onMessageClicked();
+
+    void showSyncErrorsDialog();
+
+private:
+    Q_DISABLE_COPY(SeafileTrayIcon)
+
+    void createActions();
+    void createContextMenu();
+    void createGlobalMenuBar();
+
+    QIcon stateToIcon(TrayState state);
+    QIcon getIcon(const QString& name);
+
+    QMenu *context_menu_;
+    QMenu *help_menu_;
+    QMenu *global_menu_;
+    QMenu *dock_menu_;
+    QMenuBar *global_menubar_;
+
+    // Actions for tray icon menu
+    QAction *enable_auto_sync_action_;
+    QAction *disable_auto_sync_action_;
+    QAction *quit_action_;
+    QAction *show_main_window_action_;
+    QAction *settings_action_;
+    QAction *open_seafile_folder_action_;
+    QAction *open_log_directory_action_;
+    QAction *shellext_fix_action_;
+    QAction *upload_log_directory_action_;
+    QAction *show_sync_errors_action_;
+
+    QAction *about_action_;
+    QAction *open_help_action_;
+
+#if defined(Q_OS_MAC)
+    TrayNotificationManager *tnm;
+#endif
+
+    QTimer *rotate_timer_;
+    QTimer *refresh_timer_;
+    int nth_trayicon_;
+    int rotate_counter_;
+    bool auto_sync_;
+
+    TrayState state_;
+
+    QString repo_id_;
+    QString commit_id_;
+    QString previous_commit_id_;
+
+    QHash<QString, QIcon> icon_cache_;
+
+    struct TrayMessage {
+        QString title;
+        QString message;
+        MessageIcon icon;
+        QString repo_id;
+        QString commit_id;
+        QString previous_commit_id;
+    };
+
+    // Use a queue to gurantee each tray notification message would be
+    // displayed at least several seconds.
+    QQueue<TrayMessage> pending_messages_;
+    qint64 next_message_msec_;
+
+    SyncErrorsDialog *sync_errors_dialog_;
+    AboutDialog *about_dialog_;
+    LogDirUploader *log_dir_uploader_;
+};
+
+#endif // SEAFILE_CLIENT_TRAY_ICON_H
diff --git a/src/ui/two-factor-dialog.cpp b/src/ui/two-factor-dialog.cpp
new file mode 100644 (file)
index 0000000..eb617c8
--- /dev/null
@@ -0,0 +1,32 @@
+#include "two-factor-dialog.h"
+#include "seafile-applet.h"
+
+TwoFactorDialog::TwoFactorDialog(QWidget *parent) :
+    QDialog(parent)
+{
+    setupUi(this);
+    mText->setText(tr("Enter the two factor authentication token"));
+    setWindowTitle(tr("Two Factor Authentication"));
+    setWindowIcon(QIcon(":/images/seafile.png"));
+
+    connect(mSubmit, SIGNAL(clicked()), this, SLOT(doSubmit()));
+}
+
+QString TwoFactorDialog::getText()
+{
+    return mLineEdit->text();
+}
+
+bool TwoFactorDialog::rememberDeviceChecked()
+{
+    return mRememberDevice->isChecked();
+}
+
+void TwoFactorDialog::doSubmit()
+{
+    if (!mLineEdit->text().isEmpty()) {
+        accept();
+    } else {
+        seafApplet->warningBox(tr("Please enter the two factor authentication token"));
+    }
+}
diff --git a/src/ui/two-factor-dialog.h b/src/ui/two-factor-dialog.h
new file mode 100644 (file)
index 0000000..26cd94e
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef TWOFACTORDIALOG_H
+#define TWOFACTORDIALOG_H
+
+#include <QDialog>
+#include "ui_two-factor-dialog.h"
+class TwoFactorDialog : public QDialog,
+                        public Ui::TwoFactorDialog
+{
+    Q_OBJECT
+
+public:
+    TwoFactorDialog(QWidget *parent = 0);
+    QString getText();
+    bool rememberDeviceChecked();
+
+private slots:
+    void doSubmit();
+};
+
+#endif // TWOFACTORDIALOG_H
diff --git a/src/ui/uninstall-helper-dialog.cpp b/src/ui/uninstall-helper-dialog.cpp
new file mode 100644 (file)
index 0000000..8d2c695
--- /dev/null
@@ -0,0 +1,95 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "utils/uninstall-helpers.h"
+
+#include "uninstall-helper-dialog.h"
+
+
+UninstallHelperDialog::UninstallHelperDialog(QWidget *parent)
+    : QDialog(parent)
+{
+    setupUi(this);
+    setWindowIcon(QIcon(":/images/seafile.png"));
+    setWindowTitle(tr("Uninstall %1").arg(getBrand()));
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    mText->setText(tr("Do you want to remove the %1 account information?").arg(getBrand()));
+
+    loadQss("qt.css") || loadQss(":/qt.css");
+#if defined(Q_OS_WIN32)
+    loadQss("qt-win.css") || loadQss(":/qt-win.css");
+#elif defined(Q_OS_LINUX)
+    loadQss("qt-linux.css") || loadQss(":/qt-linux.css");
+#else
+    loadQss("qt-mac.css") || loadQss(":/qt-mac.css");
+#endif
+
+    const QRect screen = QApplication::desktop()->screenGeometry();
+    move(screen.center() - this->rect().center());
+
+    connect(mYesBtn, SIGNAL(clicked()),
+            this, SLOT(onYesClicked()));
+
+    connect(mNoBtn, SIGNAL(clicked()),
+            this, SLOT(doExit()));
+}
+
+void UninstallHelperDialog::onYesClicked()
+{
+    mYesBtn->setEnabled(false);
+    mNoBtn->setEnabled(false);
+    mText->setText(tr("Removing account information..."));
+
+    RemoveSeafileDataThread *thread = new RemoveSeafileDataThread;
+    thread->start();
+    connect(thread, SIGNAL(finished()), this, SLOT(doExit()));
+}
+
+void UninstallHelperDialog::doExit()
+{
+    QCoreApplication::exit(0);
+}
+
+bool UninstallHelperDialog::loadQss(const QString& path)
+{
+    QFile file(path);
+    if (!QFileInfo(file).exists()) {
+        return false;
+    }
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        return false;
+    }
+
+    QTextStream input(&file);
+    style_ += "\n";
+    style_ += input.readAll();
+    qApp->setStyleSheet(style_);
+
+    return true;
+}
+
+void RemoveSeafileDataThread::run()
+{
+    QString ccnet_dir;
+    QString seafile_data_dir;
+
+    if (get_ccnet_dir(&ccnet_dir) < 0) {
+        fprintf (stderr, "ccnet dir not found");
+        return;
+    }
+    if (get_seafile_data_dir(ccnet_dir, &seafile_data_dir) < 0) {
+        delete_dir_recursively(ccnet_dir);
+        return;
+    }
+
+    delete_dir_recursively(ccnet_dir);
+    delete_dir_recursively(seafile_data_dir);
+}
diff --git a/src/ui/uninstall-helper-dialog.h b/src/ui/uninstall-helper-dialog.h
new file mode 100644 (file)
index 0000000..1bb7a71
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef SEAFILE_CLIENT_UNINSTALL_HELPER_WINDOW_H
+#define SEAFILE_CLIENT_UNINSTALL_HELPER_WINDOW_H
+
+#include <QThread>
+#include <QDialog>
+#include "ui_uninstall-helper-dialog.h"
+
+
+class UninstallHelperDialog : public QDialog,
+                              public Ui::UninstallHelperDialog
+{
+    Q_OBJECT
+public:
+    UninstallHelperDialog(QWidget *parent=0);
+
+private slots:
+    void onYesClicked();
+    void doExit();
+
+private:
+    Q_DISABLE_COPY(UninstallHelperDialog)
+
+    bool loadQss(const QString& path);
+
+    QString style_;
+};
+
+class RemoveSeafileDataThread : public QThread
+{
+    Q_OBJECT
+public:
+    void run();
+};
+
+
+#endif // SEAFILE_CLIENT_UNINSTALL_HELPER_WINDOW_H
diff --git a/src/ui/user-name-completer.cpp b/src/ui/user-name-completer.cpp
new file mode 100644 (file)
index 0000000..04697c7
--- /dev/null
@@ -0,0 +1,272 @@
+#include <QLineEdit>
+#include <QTimer>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QtWidgets>
+
+#include "api/api-error.h"
+#include "api/contact-share-info.h"
+#include "api/requests.h"
+#include "avatar-service.h"
+
+#include "user-name-completer.h"
+
+namespace
+{
+const int kSearchDelayInterval = 150;
+const qint64 kCacheEntryExpireMSecs = 5 * 1000;
+
+enum {
+    USER_COLUMN_AVATAR = 0,
+    USER_COLUMN_NAME,
+    USER_MAX_COLUMN
+};
+
+} // anonymous namespace
+
+SeafileUserNameCompleter::SeafileUserNameCompleter(const Account &account,
+                                                   QLineEdit *parent)
+    : QObject(parent), account_(account), editor_(parent)
+{
+    popup_ = new QTreeWidget;
+    popup_->setWindowFlags(Qt::Popup);
+    popup_->setFocusPolicy(Qt::NoFocus);
+    popup_->setFocusProxy(parent);
+    popup_->setMouseTracking(true);
+
+    popup_->setColumnCount(USER_MAX_COLUMN);
+    popup_->setUniformRowHeights(true);
+    popup_->setRootIsDecorated(false);
+    popup_->setEditTriggers(QTreeWidget::NoEditTriggers);
+    popup_->setSelectionBehavior(QTreeWidget::SelectRows);
+    popup_->setFrameStyle(QFrame::Box | QFrame::Plain);
+    popup_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    popup_->header()->hide();
+
+    popup_->installEventFilter(this);
+
+    connect(popup_,
+            SIGNAL(itemClicked(QTreeWidgetItem *, int)),
+            SLOT(doneCompletion()));
+
+    timer_ = new QTimer(this);
+    timer_->setSingleShot(true);
+    timer_->setInterval(kSearchDelayInterval);
+    connect(timer_, SIGNAL(timeout()), SLOT(autoSuggest()));
+    // Calling start on the timer would effectively stop it & restart again.
+    // Thus we can achieve: only show the completion list when the user has not
+    // typed for a little while, here 150ms.
+    connect(editor_, SIGNAL(textEdited(QString)), timer_, SLOT(start()));
+
+    connect(AvatarService::instance(), SIGNAL(avatarUpdated(const QString&, const QImage&)),
+            this, SLOT(onAvatarUpdated(const QString&, const QImage&)));
+}
+
+SeafileUserNameCompleter::~SeafileUserNameCompleter()
+{
+    popup_->deleteLater();
+}
+
+bool SeafileUserNameCompleter::eventFilter(QObject *obj, QEvent *ev)
+{
+    if (obj != popup_)
+        return false;
+
+    if (ev->type() == QEvent::MouseButtonPress) {
+        popup_->hide();
+        editor_->setFocus();
+        return true;
+    }
+
+    if (ev->type() == QEvent::KeyPress) {
+        bool consumed = false;
+        int key = static_cast<QKeyEvent *>(ev)->key();
+        switch (key) {
+            case Qt::Key_Enter:
+            case Qt::Key_Return:
+                doneCompletion();
+                consumed = true;
+                break;
+
+            case Qt::Key_Escape:
+                popup_->hide();
+                editor_->setFocus();
+                consumed = true;
+                break;
+
+            // Pass through the item navigation opeations to the tree widget.
+            case Qt::Key_Up:
+            case Qt::Key_Down:
+            case Qt::Key_Home:
+            case Qt::Key_End:
+            case Qt::Key_PageUp:
+            case Qt::Key_PageDown:
+                break;
+
+            default:
+                editor_->setFocus();
+                editor_->event(ev);
+                popup_->hide();
+                break;
+        }
+
+        return consumed;
+    }
+
+    return false;
+}
+
+void SeafileUserNameCompleter::showCompletion(const QList<SeafileUser> &users, const QString& pattern)
+{
+    if (users.isEmpty())
+        return;
+
+    if (pattern != editor_->text().trimmed()) {
+        // The user has changed the text, so the completions are no longer
+        // useful.
+        // printf("pattern changed from \"%s\" to \"%s\"\n",
+        //        pattern.toUtf8().data(),
+        //        editor_->text().trimmed().toUtf8().data());
+        return;
+    }
+
+    popup_->setUpdatesEnabled(false);
+    popup_->clear();
+    foreach (const SeafileUser &user, users) {
+        // Do not list the user itself in the completion list.
+        if (user.email == account_.username) {
+            continue;
+        }
+
+        AvatarService *service = AvatarService::instance();
+        QIcon avatar = QPixmap::fromImage(service->getAvatar(user.email));
+
+        QString text =
+            QString("%1 <%2>").arg(user.name).arg(user.getDisplayEmail());
+        QTreeWidgetItem *item;
+        item = new QTreeWidgetItem(popup_);
+        item->setIcon(USER_COLUMN_AVATAR, avatar);
+        item->setText(USER_COLUMN_NAME, text);
+        item->setData(USER_COLUMN_NAME, Qt::UserRole, QVariant::fromValue(user));
+    }
+    popup_->setCurrentItem(popup_->topLevelItem(0));
+    popup_->resizeColumnToContents(USER_COLUMN_AVATAR);
+    popup_->setUpdatesEnabled(true);
+
+    popup_->move(editor_->mapToGlobal(QPoint(0, editor_->height())));
+
+    int w = editor_->width();
+    int maxVisibleItems = 7;
+    int h = (popup_->sizeHintForRow(0) *
+                 qMin(maxVisibleItems, popup_->model()->rowCount()) +
+             3) +
+            3;
+    h = qMax(h, popup_->minimumHeight());
+    // printf("w = %d, h = %d\n", w, h);
+
+    QPoint pos = editor_->mapToGlobal(QPoint(0, editor_->height()));
+    popup_->setGeometry(pos.x(), pos.y(), w, h);
+
+    popup_->setFocus();
+    if (!popup_->isVisible())
+        popup_->show();
+}
+
+void SeafileUserNameCompleter::doneCompletion()
+{
+    timer_->stop();
+    popup_->hide();
+    editor_->setFocus();
+    QTreeWidgetItem *item = popup_->currentItem();
+    if (item) {
+        SeafileUser user = item->data(USER_COLUMN_NAME, Qt::UserRole).value<SeafileUser>();
+        current_selected_user_ = user;
+        editor_->setText(user.name);
+        QMetaObject::invokeMethod(editor_, "returnPressed");
+    }
+}
+
+void SeafileUserNameCompleter::autoSuggest()
+{
+    current_selected_user_ = SeafileUser();
+    QString pattern = editor_->text().trimmed();
+    if (pattern.isEmpty()) {
+        return;
+    }
+
+    if (cached_completion_users_by_pattern_.contains(pattern) &&
+        cached_completion_users_by_pattern_[pattern].ts +
+                kCacheEntryExpireMSecs >
+            QDateTime::currentMSecsSinceEpoch()) {
+        // printf("cached results for %s\n", pattern.toUtf8().data());
+        showCompletion(
+            cached_completion_users_by_pattern_[pattern].users.toList(), pattern);
+        return;
+    }
+
+    if (in_progress_search_requests_.contains(pattern)) {
+        // printf("already a request for %s\n", pattern.toUtf8().data());
+        return;
+    }
+
+    // printf("request completions for username %s\n", pattern.toUtf8().data());
+    SearchUsersRequest *req = new SearchUsersRequest(account_, pattern);
+    req->setParent(this);
+    connect(req,
+            SIGNAL(success(const QList<SeafileUser> &)),
+            this,
+            SLOT(onSearchUsersSuccess(const QList<SeafileUser> &)));
+    connect(req,
+            SIGNAL(failed(const ApiError &)),
+            this,
+            SLOT(onSearchUsersFailed(const ApiError &)));
+    req->send();
+
+    in_progress_search_requests_.insert(pattern);
+}
+
+void SeafileUserNameCompleter::preventSuggest()
+{
+    timer_->stop();
+}
+
+void SeafileUserNameCompleter::onSearchUsersSuccess(
+    const QList<SeafileUser> &users)
+{
+    SearchUsersRequest *req = qobject_cast<SearchUsersRequest *>(sender());
+    in_progress_search_requests_.remove(req->pattern());
+    req->deleteLater();
+
+    // printf("get %d results for pattern %s\n",
+    //        users.size(),
+    //        req->pattern().toUtf8().data());
+
+    cached_completion_users_by_pattern_[req->pattern()] = {
+        QSet<SeafileUser>::fromList(users),
+        QDateTime::currentMSecsSinceEpoch()};
+    showCompletion(users, req->pattern());
+}
+
+void SeafileUserNameCompleter::onSearchUsersFailed(const ApiError &error)
+{
+    SearchUsersRequest *req = qobject_cast<SearchUsersRequest *>(sender());
+    in_progress_search_requests_.remove(req->pattern());
+    req->deleteLater();
+}
+
+const SeafileUser& SeafileUserNameCompleter::currentSelectedUser() const
+{
+    return current_selected_user_;
+}
+
+void SeafileUserNameCompleter::onAvatarUpdated(const QString& email,
+                                               const QImage& avatar)
+{
+    for (int i = 0; i < popup_->topLevelItemCount(); i++) {
+        QTreeWidgetItem* item =  popup_->topLevelItem(i);
+        const QString username_email = item->data(USER_COLUMN_NAME, Qt::DisplayRole).toString();
+        if (username_email.contains(email)) {
+            item->setIcon(USER_COLUMN_AVATAR, QPixmap::fromImage(avatar));
+        }
+    }
+}
diff --git a/src/ui/user-name-completer.h b/src/ui/user-name-completer.h
new file mode 100644 (file)
index 0000000..b5d624c
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef SEAFILE_CLIENT_UI_USER_NAME_COMPLETER_H
+#define SEAFILE_CLIENT_UI_USER_NAME_COMPLETER_H
+
+#include <QObject>
+
+class QLineEdit;
+class QTimer;
+class QTreeWidget;
+
+struct SeafileUser;
+class ApiError;
+
+#include "account.h"
+#include "api/contact-share-info.h"
+#include "api/requests.h"
+
+class SeafileUserNameCompleter : public QObject
+{
+    Q_OBJECT
+
+public:
+    SeafileUserNameCompleter(const Account& account, QLineEdit *parent = 0);
+    ~SeafileUserNameCompleter();
+    bool eventFilter(QObject *obj, QEvent *ev) Q_DECL_OVERRIDE;
+
+    const SeafileUser& currentSelectedUser() const;
+
+private slots:
+    void onSearchUsersSuccess(const QList<SeafileUser>& contacts);
+    void onSearchUsersFailed(const ApiError& error);
+    void doneCompletion();
+    void preventSuggest();
+    void autoSuggest();
+    void showCompletion(const QList<SeafileUser>& users, const QString& pattern);
+    void onAvatarUpdated(const QString& email, const QImage& avatar);
+
+private:
+    Account account_;
+
+    QLineEdit *editor_;
+    QTreeWidget *popup_;
+    QTimer *timer_;
+
+    QSet<QString> in_progress_search_requests_;
+
+    struct CachedUsersEntry {
+        QSet<SeafileUser> users;
+        qint64 ts;
+    };
+    QHash<QString, CachedUsersEntry> cached_completion_users_by_pattern_;
+
+    SeafileUser current_selected_user_;
+};
+
+#endif // SEAFILE_CLIENT_UI_USER_NAME_COMPLETER_H
diff --git a/src/utils/api-utils.cpp b/src/utils/api-utils.cpp
new file mode 100644 (file)
index 0000000..4264af8
--- /dev/null
@@ -0,0 +1,39 @@
+#include <QHash>
+#include <QHostInfo>
+
+#include "utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "api-utils.h"
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+const char *kOsName = "windows";
+#elif defined(Q_OS_LINUX)
+const char *kOsName = "linux";
+#else
+const char *kOsName = "mac";
+#endif
+
+} // namespace
+
+QHash<QString, QString>
+getSeafileLoginParams(const QString& computer_name, const QString& prefix)
+{
+
+    QHash<QString, QString> params;
+
+    QString client_version = STRINGIZE(SEAFILE_CLIENT_VERSION);
+    QString device_id = seafApplet->getUniqueClientId();
+    QString computper = computer_name.isEmpty() ? QHostInfo::localHostName() 
+        : computer_name;
+
+    params.insert(prefix + "platform", kOsName);
+    params.insert(prefix + "device_id", device_id);
+    params.insert(prefix + "device_name", computer_name);
+    params.insert(prefix + "client_version", client_version);
+    params.insert(prefix + "platform_version", "");
+
+    return params;
+}
diff --git a/src/utils/api-utils.h b/src/utils/api-utils.h
new file mode 100644 (file)
index 0000000..1df95e8
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef SEAFILE_CLIENT_API_UTILS_H_
+#define SEAFILE_CLIENT_API_UTILS_H_
+
+QHash<QString, QString>
+getSeafileLoginParams(const QString& computer_name=QString(),
+                      const QString& prefix=QString());
+
+#endif // SEAFILE_CLIENT_API_UTILS_H_
diff --git a/src/utils/file-utils.cpp b/src/utils/file-utils.cpp
new file mode 100644 (file)
index 0000000..99103aa
--- /dev/null
@@ -0,0 +1,845 @@
+#include <QHash>
+#include <QFileInfo>
+#include <QDir>
+#include <QStringList>
+#include "stl.h"
+
+#ifdef Q_OS_WIN32
+#include <windows.h>
+#endif
+
+#include "file-utils.h"
+
+namespace {
+
+QHash<QString, QString> *types_map = 0;
+
+void init()
+{
+    types_map = new QHash<QString, QString>;
+
+    // Adapted from /etc/mime.types on ubuntu 12.04
+    // TODO: on windows we should read the system registry for a more complete mime types list
+
+    types_map->insert("%", "application/x-trash");
+    types_map->insert("323", "text/h323");
+    types_map->insert("3gp", "video/3gpp");
+    types_map->insert("7z", "application/x-7z-compressed");
+    types_map->insert("a", "application/octet-stream");
+    types_map->insert("abw", "application/x-abiword");
+    types_map->insert("ai", "application/postscript");
+    types_map->insert("aif", "audio/x-aiff");
+    types_map->insert("aifc", "audio/x-aiff");
+    types_map->insert("aiff", "audio/x-aiff");
+    types_map->insert("alc", "chemical/x-alchemy");
+    types_map->insert("amr", "audio/amr");
+    types_map->insert("anx", "application/annodex");
+    types_map->insert("apk", "application/vnd.android.package-archive");
+    types_map->insert("art", "image/x-jg");
+    types_map->insert("asc", "text/plain");
+    types_map->insert("asf", "video/x-ms-asf");
+    types_map->insert("asn", "chemical/x-ncbi-asn1-spec");
+    types_map->insert("aso", "chemical/x-ncbi-asn1-binary");
+    types_map->insert("asx", "video/x-ms-asf");
+    types_map->insert("atom", "application/atom+xml");
+    types_map->insert("atomcat", "application/atomcat+xml");
+    types_map->insert("atomsrv", "application/atomserv+xml");
+    types_map->insert("au", "audio/basic");
+    types_map->insert("avi", "video/x-msvideo");
+    types_map->insert("awb", "audio/amr-wb");
+    types_map->insert("axa", "audio/annodex");
+    types_map->insert("axv", "video/annodex");
+    types_map->insert("b", "chemical/x-molconn-Z");
+    types_map->insert("bak", "application/x-trash");
+    types_map->insert("bat", "application/x-msdos-program");
+    types_map->insert("bcpio", "application/x-bcpio");
+    types_map->insert("bib", "text/x-bibtex");
+    types_map->insert("bin", "application/octet-stream");
+    types_map->insert("bmp", "image/x-ms-bmp");
+    types_map->insert("boo", "text/x-boo");
+    types_map->insert("book", "application/x-maker");
+    types_map->insert("brf", "text/plain");
+    types_map->insert("bsd", "chemical/x-crossfire");
+    types_map->insert("c", "text/x-csrc");
+    types_map->insert("c++", "text/x-c++src");
+    types_map->insert("c3d", "chemical/x-chem3d");
+    types_map->insert("cab", "application/x-cab");
+    types_map->insert("cac", "chemical/x-cache");
+    types_map->insert("cache", "chemical/x-cache");
+    types_map->insert("cap", "application/cap");
+    types_map->insert("cascii", "chemical/x-cactvs-binary");
+    types_map->insert("cat", "application/vnd.ms-pki.seccat");
+    types_map->insert("cbin", "chemical/x-cactvs-binary");
+    types_map->insert("cbr", "application/x-cbr");
+    types_map->insert("cbz", "application/x-cbz");
+    types_map->insert("cc", "text/x-c++src");
+    types_map->insert("cda", "application/x-cdf");
+    types_map->insert("cdf", "application/x-cdf");
+    types_map->insert("cdr", "image/x-coreldraw");
+    types_map->insert("cdt", "image/x-coreldrawtemplate");
+    types_map->insert("cdx", "chemical/x-cdx");
+    types_map->insert("cdy", "application/vnd.cinderella");
+    types_map->insert("cef", "chemical/x-cxf");
+    types_map->insert("cer", "chemical/x-cerius");
+    types_map->insert("chm", "chemical/x-chemdraw");
+    types_map->insert("chrt", "application/x-kchart");
+    types_map->insert("cif", "chemical/x-cif");
+    types_map->insert("class", "application/java-vm");
+    types_map->insert("cls", "text/x-tex");
+    types_map->insert("cmdf", "chemical/x-cmdf");
+    types_map->insert("cml", "chemical/x-cml");
+    types_map->insert("cod", "application/vnd.rim.cod");
+    types_map->insert("com", "application/x-msdos-program");
+    types_map->insert("cpa", "chemical/x-compass");
+    types_map->insert("cpio", "application/x-cpio");
+    types_map->insert("cpp", "text/x-c++src");
+    types_map->insert("cpt", "image/x-corelphotopaint");
+    types_map->insert("cr2", "image/x-canon-cr2");
+    types_map->insert("crl", "application/x-pkcs7-crl");
+    types_map->insert("crt", "application/x-x509-ca-cert");
+    types_map->insert("crw", "image/x-canon-crw");
+    types_map->insert("csd", "audio/csound");
+    types_map->insert("csf", "chemical/x-cache-csf");
+    types_map->insert("csh", "text/x-csh");
+    types_map->insert("csm", "chemical/x-csml");
+    types_map->insert("csml", "chemical/x-csml");
+    types_map->insert("css", "text/css");
+    types_map->insert("csv", "text/csv");
+    types_map->insert("ctab", "chemical/x-cactvs-binary");
+    types_map->insert("ctx", "chemical/x-ctx");
+    types_map->insert("cu", "application/cu-seeme");
+    types_map->insert("cub", "chemical/x-gaussian-cube");
+    types_map->insert("cxf", "chemical/x-cxf");
+    types_map->insert("cxx", "text/x-c++src");
+    types_map->insert("d", "text/x-dsrc");
+    types_map->insert("dat", "application/x-ns-proxy-autoconfig");
+    types_map->insert("davmount", "application/davmount+xml");
+    types_map->insert("dcr", "application/x-director");
+    types_map->insert("deb", "application/x-debian-package");
+    types_map->insert("dif", "video/dv");
+    types_map->insert("diff", "text/x-diff");
+    types_map->insert("dir", "application/x-director");
+    types_map->insert("djv", "image/vnd.djvu");
+    types_map->insert("djvu", "image/vnd.djvu");
+    types_map->insert("dl", "video/dl");
+    types_map->insert("dll", "application/x-msdos-program");
+    types_map->insert("dmg", "application/x-apple-diskimage");
+    types_map->insert("dms", "application/x-dms");
+    types_map->insert("doc", "application/msword");
+    types_map->insert("docm", "application/vnd.ms-word.document.macroEnabled.12");
+    types_map->insert("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+    types_map->insert("dot", "application/msword");
+    types_map->insert("dotm", "application/vnd.ms-word.template.macroEnabled.12");
+    types_map->insert("dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template");
+    types_map->insert("dv", "video/dv");
+    types_map->insert("dvi", "application/x-dvi");
+    types_map->insert("dx", "chemical/x-jcamp-dx");
+    types_map->insert("dxr", "application/x-director");
+    types_map->insert("emb", "chemical/x-embl-dl-nucleotide");
+    types_map->insert("embl", "chemical/x-embl-dl-nucleotide");
+    types_map->insert("eml", "message/rfc822");
+    types_map->insert("ent", "chemical/x-pdb");
+    types_map->insert("eps", "application/postscript");
+    types_map->insert("eps2", "application/postscript");
+    types_map->insert("eps3", "application/postscript");
+    types_map->insert("epsf", "application/postscript");
+    types_map->insert("epsi", "application/postscript");
+    types_map->insert("erf", "image/x-epson-erf");
+    types_map->insert("es", "application/ecmascript");
+    types_map->insert("etx", "text/x-setext");
+    types_map->insert("exe", "application/x-msdos-program");
+    types_map->insert("ez", "application/andrew-inset");
+    types_map->insert("fb", "application/x-maker");
+    types_map->insert("fbdoc", "application/x-maker");
+    types_map->insert("fch", "chemical/x-gaussian-checkpoint");
+    types_map->insert("fchk", "chemical/x-gaussian-checkpoint");
+    types_map->insert("fig", "application/x-xfig");
+    types_map->insert("flac", "audio/flac");
+    types_map->insert("fli", "video/fli");
+    types_map->insert("flv", "video/x-flv");
+    types_map->insert("fm", "application/x-maker");
+    types_map->insert("fodg", "application/vnd.oasis.opendocument.graphics-flat-xml");
+    types_map->insert("fodp", "application/vnd.oasis.opendocument.presentation-flat-xml");
+    types_map->insert("fods", "application/vnd.oasis.opendocument.spreadsheet-flat-xml");
+    types_map->insert("fodt", "application/vnd.oasis.opendocument.text-flat-xml");
+    types_map->insert("frame", "application/x-maker");
+    types_map->insert("frm", "application/x-maker");
+    types_map->insert("gal", "chemical/x-gaussian-log");
+    types_map->insert("gam", "chemical/x-gamess-input");
+    types_map->insert("gamin", "chemical/x-gamess-input");
+    types_map->insert("gan", "application/x-ganttproject");
+    types_map->insert("gau", "chemical/x-gaussian-input");
+    types_map->insert("gcd", "text/x-pcs-gcd");
+    types_map->insert("gcf", "application/x-graphing-calculator");
+    types_map->insert("gcg", "chemical/x-gcg8-sequence");
+    types_map->insert("gen", "chemical/x-genbank");
+    types_map->insert("gf", "application/x-tex-gf");
+    types_map->insert("gif", "image/gif");
+    types_map->insert("gjc", "chemical/x-gaussian-input");
+    types_map->insert("gjf", "chemical/x-gaussian-input");
+    types_map->insert("gl", "video/gl");
+    types_map->insert("gnumeric", "application/x-gnumeric");
+    types_map->insert("gpt", "chemical/x-mopac-graph");
+    types_map->insert("gsf", "application/x-font");
+    types_map->insert("gsm", "audio/x-gsm");
+    types_map->insert("gtar", "application/x-gtar");
+    types_map->insert("h", "text/x-chdr");
+    types_map->insert("h++", "text/x-c++hdr");
+    types_map->insert("hdf", "application/x-hdf");
+    types_map->insert("hh", "text/x-c++hdr");
+    types_map->insert("hin", "chemical/x-hin");
+    types_map->insert("hpp", "text/x-c++hdr");
+    types_map->insert("hqx", "application/mac-binhex40");
+    types_map->insert("hs", "text/x-haskell");
+    types_map->insert("hta", "application/hta");
+    types_map->insert("htc", "text/x-component");
+    types_map->insert("htm", "text/html");
+    types_map->insert("html", "text/html");
+    types_map->insert("hxx", "text/x-c++hdr");
+    types_map->insert("ica", "application/x-ica");
+    types_map->insert("ice", "x-conference/x-cooltalk");
+    types_map->insert("ico", "image/x-icon");
+    types_map->insert("ics", "text/calendar");
+    types_map->insert("icz", "text/calendar");
+    types_map->insert("ief", "image/ief");
+    types_map->insert("iges", "model/iges");
+    types_map->insert("igs", "model/iges");
+    types_map->insert("iii", "application/x-iphone");
+    types_map->insert("info", "application/x-info");
+    types_map->insert("inp", "chemical/x-gamess-input");
+    types_map->insert("ins", "application/x-internet-signup");
+    types_map->insert("iso", "application/x-iso9660-image");
+    types_map->insert("isp", "application/x-internet-signup");
+    types_map->insert("ist", "chemical/x-isostar");
+    types_map->insert("istr", "chemical/x-isostar");
+    types_map->insert("jad", "text/vnd.sun.j2me.app-descriptor");
+    types_map->insert("jam", "application/x-jam");
+    types_map->insert("jar", "application/java-archive");
+    types_map->insert("java", "text/x-java");
+    types_map->insert("jdx", "chemical/x-jcamp-dx");
+    types_map->insert("jmz", "application/x-jmol");
+    types_map->insert("jng", "image/x-jng");
+    types_map->insert("jnlp", "application/x-java-jnlp-file");
+    types_map->insert("jpe", "image/jpeg");
+    types_map->insert("jpeg", "image/jpeg");
+    types_map->insert("jpg", "image/jpeg");
+    types_map->insert("js", "application/javascript");
+    types_map->insert("json", "application/json");
+    types_map->insert("kar", "audio/midi");
+    types_map->insert("key", "application/pgp-keys");
+    types_map->insert("kil", "application/x-killustrator");
+    types_map->insert("kin", "chemical/x-kinemage");
+    types_map->insert("kml", "application/vnd.google-earth.kml+xml");
+    types_map->insert("kmz", "application/vnd.google-earth.kmz");
+    types_map->insert("kpr", "application/x-kpresenter");
+    types_map->insert("kpt", "application/x-kpresenter");
+    types_map->insert("ksh", "text/plain");
+    types_map->insert("ksp", "application/x-kspread");
+    types_map->insert("kwd", "application/x-kword");
+    types_map->insert("kwt", "application/x-kword");
+    types_map->insert("latex", "application/x-latex");
+    types_map->insert("lha", "application/x-lha");
+    types_map->insert("lhs", "text/x-literate-haskell");
+    types_map->insert("lin", "application/bbolin");
+    types_map->insert("lsf", "video/x-la-asf");
+    types_map->insert("lsx", "video/x-la-asf");
+    types_map->insert("ltx", "text/x-tex");
+    types_map->insert("lyx", "application/x-lyx");
+    types_map->insert("lzh", "application/x-lzh");
+    types_map->insert("lzx", "application/x-lzx");
+    types_map->insert("m1v", "video/mpeg");
+    types_map->insert("m3g", "application/m3g");
+    types_map->insert("m3u", "audio/x-mpegurl");
+    types_map->insert("m3u8", "application/x-mpegURL");
+    types_map->insert("m4a", "audio/mpeg");
+    types_map->insert("maker", "application/x-maker");
+    types_map->insert("man", "application/x-troff-man");
+    types_map->insert("manifest", "text/cache-manifest");
+    types_map->insert("mcif", "chemical/x-mmcif");
+    types_map->insert("mcm", "chemical/x-macmolecule");
+    types_map->insert("mdb", "application/msaccess");
+    types_map->insert("me", "application/x-troff-me");
+    types_map->insert("mesh", "model/mesh");
+    types_map->insert("mht", "message/rfc822");
+    types_map->insert("mhtml", "message/rfc822");
+    types_map->insert("mid", "audio/midi");
+    types_map->insert("midi", "audio/midi");
+    types_map->insert("mif", "application/x-mif");
+    types_map->insert("mkv", "video/x-matroska");
+    types_map->insert("mm", "application/x-freemind");
+    types_map->insert("mmd", "chemical/x-macromodel-input");
+    types_map->insert("mmf", "application/vnd.smaf");
+    types_map->insert("mml", "text/mathml");
+    types_map->insert("mmod", "chemical/x-macromodel-input");
+    types_map->insert("mng", "video/x-mng");
+    types_map->insert("moc", "text/x-moc");
+    types_map->insert("mol", "chemical/x-mdl-molfile");
+    types_map->insert("mol2", "chemical/x-mol2");
+    types_map->insert("moo", "chemical/x-mopac-out");
+    types_map->insert("mop", "chemical/x-mopac-input");
+    types_map->insert("mopcrt", "chemical/x-mopac-input");
+    types_map->insert("mov", "video/quicktime");
+    types_map->insert("movie", "video/x-sgi-movie");
+    types_map->insert("mp2", "audio/mpeg");
+    types_map->insert("mp3", "audio/mpeg");
+    types_map->insert("mp4", "video/mp4");
+    types_map->insert("mpa", "video/mpeg");
+    types_map->insert("mpc", "chemical/x-mopac-input");
+    types_map->insert("mpe", "video/mpeg");
+    types_map->insert("mpeg", "video/mpeg");
+    types_map->insert("mpega", "audio/mpeg");
+    types_map->insert("mpg", "video/mpeg");
+    types_map->insert("mpga", "audio/mpeg");
+    types_map->insert("mph", "application/x-comsol");
+    types_map->insert("mpv", "video/x-matroska");
+    types_map->insert("ms", "application/x-troff-ms");
+    types_map->insert("msh", "model/mesh");
+    types_map->insert("msi", "application/x-msi");
+    types_map->insert("mvb", "chemical/x-mopac-vib");
+    types_map->insert("mxf", "application/mxf");
+    types_map->insert("mxu", "video/vnd.mpegurl");
+    types_map->insert("nb", "application/mathematica");
+    types_map->insert("nbp", "application/mathematica");
+    types_map->insert("nc", "application/x-netcdf");
+    types_map->insert("nef", "image/x-nikon-nef");
+    types_map->insert("nwc", "application/x-nwc");
+    types_map->insert("nws", "message/rfc822");
+    types_map->insert("o", "application/x-object");
+    types_map->insert("obj", "application/octet-stream");
+    types_map->insert("oda", "application/oda");
+    types_map->insert("odb", "application/vnd.sun.xml.base");
+    types_map->insert("odc", "application/vnd.oasis.opendocument.chart");
+    types_map->insert("odf", "application/vnd.oasis.opendocument.formula");
+    types_map->insert("odg", "application/vnd.oasis.opendocument.graphics");
+    types_map->insert("odi", "application/vnd.oasis.opendocument.image");
+    types_map->insert("odm", "application/vnd.oasis.opendocument.text-master");
+    types_map->insert("odp", "application/vnd.oasis.opendocument.presentation");
+    types_map->insert("ods", "application/vnd.oasis.opendocument.spreadsheet");
+    types_map->insert("odt", "application/vnd.oasis.opendocument.text");
+    types_map->insert("oga", "audio/ogg");
+    types_map->insert("ogg", "audio/ogg");
+    types_map->insert("ogv", "video/ogg");
+    types_map->insert("ogx", "application/ogg");
+    types_map->insert("old", "application/x-trash");
+    types_map->insert("one", "application/onenote");
+    types_map->insert("onepkg", "application/onenote");
+    types_map->insert("onetmp", "application/onenote");
+    types_map->insert("onetoc2", "application/onenote");
+    types_map->insert("orc", "audio/csound");
+    types_map->insert("orf", "image/x-olympus-orf");
+    types_map->insert("otg", "application/vnd.oasis.opendocument.graphics-template");
+    types_map->insert("oth", "application/vnd.oasis.opendocument.text-web");
+    types_map->insert("otp", "application/vnd.oasis.opendocument.presentation-template");
+    types_map->insert("ots", "application/vnd.oasis.opendocument.spreadsheet-template");
+    types_map->insert("ott", "application/vnd.oasis.opendocument.text-template");
+    types_map->insert("oxt", "application/vnd.openofficeorg.extension");
+    types_map->insert("oza", "application/x-oz-application");
+    types_map->insert("p", "text/x-pascal");
+    types_map->insert("p12", "application/x-pkcs12");
+    types_map->insert("p7c", "application/pkcs7-mime");
+    types_map->insert("p7r", "application/x-pkcs7-certreqresp");
+    types_map->insert("pac", "application/x-ns-proxy-autoconfig");
+    types_map->insert("pas", "text/x-pascal");
+    types_map->insert("pat", "image/x-coreldrawpattern");
+    types_map->insert("patch", "text/x-diff");
+    types_map->insert("pbm", "image/x-portable-bitmap");
+    types_map->insert("pcap", "application/cap");
+    types_map->insert("pcf", "application/x-font");
+    types_map->insert("pcf.Z", "application/x-font");
+    types_map->insert("pcx", "image/pcx");
+    types_map->insert("pdb", "chemical/x-pdb");
+    types_map->insert("pdf", "application/pdf");
+    types_map->insert("pfa", "application/x-font");
+    types_map->insert("pfb", "application/x-font");
+    types_map->insert("pfx", "application/x-pkcs12");
+    types_map->insert("pgm", "image/x-portable-graymap");
+    types_map->insert("pgn", "application/x-chess-pgn");
+    types_map->insert("pgp", "application/pgp-signature");
+    types_map->insert("php", "application/x-httpd-php");
+    types_map->insert("php3", "application/x-httpd-php3");
+    types_map->insert("php3p", "application/x-httpd-php3-preprocessed");
+    types_map->insert("php4", "application/x-httpd-php4");
+    types_map->insert("php5", "application/x-httpd-php5");
+    types_map->insert("phps", "application/x-httpd-php-source");
+    types_map->insert("pht", "application/x-httpd-php");
+    types_map->insert("phtml", "application/x-httpd-php");
+    types_map->insert("pk", "application/x-tex-pk");
+    types_map->insert("pl", "text/x-perl");
+    types_map->insert("pls", "audio/x-scpls");
+    types_map->insert("pm", "text/x-perl");
+    types_map->insert("png", "image/png");
+    types_map->insert("pnm", "image/x-portable-anymap");
+    types_map->insert("pot", "text/plain");
+    types_map->insert("potm", "application/vnd.ms-powerpoint.template.macroEnabled.12");
+    types_map->insert("potx", "application/vnd.openxmlformats-officedocument.presentationml.template");
+    types_map->insert("ppa", "application/vnd.ms-powerpoint");
+    types_map->insert("ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12");
+    types_map->insert("ppm", "image/x-portable-pixmap");
+    types_map->insert("pps", "application/vnd.ms-powerpoint");
+    types_map->insert("ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12");
+    types_map->insert("ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow");
+    types_map->insert("ppt", "application/vnd.ms-powerpoint");
+    types_map->insert("pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12");
+    types_map->insert("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
+    types_map->insert("prf", "application/pics-rules");
+    types_map->insert("prt", "chemical/x-ncbi-asn1-ascii");
+    types_map->insert("ps", "application/postscript");
+    types_map->insert("psd", "image/x-photoshop");
+    types_map->insert("pwz", "application/vnd.ms-powerpoint");
+    types_map->insert("py", "text/x-python");
+    types_map->insert("pyc", "application/x-python-code");
+    types_map->insert("pyo", "application/x-python-code");
+    types_map->insert("qgs", "application/x-qgis");
+    types_map->insert("qt", "video/quicktime");
+    types_map->insert("qtl", "application/x-quicktimeplayer");
+    types_map->insert("ra", "audio/x-realaudio");
+    types_map->insert("ram", "audio/x-pn-realaudio");
+    types_map->insert("rar", "application/rar");
+    types_map->insert("ras", "image/x-cmu-raster");
+    types_map->insert("rb", "application/x-ruby");
+    types_map->insert("rd", "chemical/x-mdl-rdfile");
+    types_map->insert("rdf", "application/rdf+xml");
+    types_map->insert("rdp", "application/x-rdp");
+    types_map->insert("rgb", "image/x-rgb");
+    types_map->insert("rhtml", "application/x-httpd-eruby");
+    types_map->insert("rm", "audio/x-pn-realaudio");
+    types_map->insert("roff", "application/x-troff");
+    types_map->insert("ros", "chemical/x-rosdal");
+    types_map->insert("rpm", "application/x-redhat-package-manager");
+    types_map->insert("rss", "application/rss+xml");
+    types_map->insert("rtf", "application/rtf");
+    types_map->insert("rtx", "text/richtext");
+    types_map->insert("rxn", "chemical/x-mdl-rxnfile");
+    types_map->insert("scala", "text/x-scala");
+    types_map->insert("sce", "application/x-scilab");
+    types_map->insert("sci", "application/x-scilab");
+    types_map->insert("sco", "audio/csound");
+    types_map->insert("scr", "application/x-silverlight");
+    types_map->insert("sct", "text/scriptlet");
+    types_map->insert("sd", "chemical/x-mdl-sdfile");
+    types_map->insert("sd2", "audio/x-sd2");
+    types_map->insert("sda", "application/vnd.stardivision.draw");
+    types_map->insert("sdc", "application/vnd.stardivision.calc");
+    types_map->insert("sdd", "application/vnd.stardivision.impress");
+    types_map->insert("sdf", "chemical/x-mdl-sdfile");
+    types_map->insert("sdp", "application/vnd.stardivision.impress");
+    types_map->insert("sds", "application/vnd.stardivision.chart");
+    types_map->insert("sdw", "application/vnd.stardivision.writer");
+    types_map->insert("ser", "application/java-serialized-object");
+    types_map->insert("sfv", "text/x-sfv");
+    types_map->insert("sgf", "application/x-go-sgf");
+    types_map->insert("sgl", "application/vnd.stardivision.writer-global");
+    types_map->insert("sgm", "text/x-sgml");
+    types_map->insert("sgml", "text/x-sgml");
+    types_map->insert("sh", "text/x-sh");
+    types_map->insert("shar", "application/x-shar");
+    types_map->insert("shp", "application/x-qgis");
+    types_map->insert("shtml", "text/html");
+    types_map->insert("shx", "application/x-qgis");
+    types_map->insert("sid", "audio/prs.sid");
+    types_map->insert("sik", "application/x-trash");
+    types_map->insert("silo", "model/mesh");
+    types_map->insert("sis", "application/vnd.symbian.install");
+    types_map->insert("sisx", "x-epoc/x-sisx-app");
+    types_map->insert("sit", "application/x-stuffit");
+    types_map->insert("sitx", "application/x-stuffit");
+    types_map->insert("skd", "application/x-koan");
+    types_map->insert("skm", "application/x-koan");
+    types_map->insert("skp", "application/x-koan");
+    types_map->insert("skt", "application/x-koan");
+    types_map->insert("sldm", "application/vnd.ms-powerpoint.slide.macroEnabled.12");
+    types_map->insert("sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide");
+    types_map->insert("smf", "application/vnd.stardivision.math");
+    types_map->insert("smi", "application/smil");
+    types_map->insert("smil", "application/smil");
+    types_map->insert("snd", "audio/basic");
+    types_map->insert("so", "application/octet-stream");
+    types_map->insert("spc", "chemical/x-galactic-spc");
+    types_map->insert("spl", "application/x-futuresplash");
+    types_map->insert("spx", "audio/ogg");
+    types_map->insert("sql", "application/x-sql");
+    types_map->insert("src", "application/x-wais-source");
+    types_map->insert("stc", "application/vnd.sun.xml.calc.template");
+    types_map->insert("std", "application/vnd.sun.xml.draw.template");
+    types_map->insert("sti", "application/vnd.sun.xml.impress.template");
+    types_map->insert("stl", "application/sla");
+    types_map->insert("stw", "application/vnd.sun.xml.writer.template");
+    types_map->insert("sty", "text/x-tex");
+    types_map->insert("sv4cpio", "application/x-sv4cpio");
+    types_map->insert("sv4crc", "application/x-sv4crc");
+    types_map->insert("svg", "image/svg+xml");
+    types_map->insert("svgz", "image/svg+xml");
+    types_map->insert("sw", "chemical/x-swissprot");
+    types_map->insert("swf", "application/x-shockwave-flash");
+    types_map->insert("swfl", "application/x-shockwave-flash");
+    types_map->insert("sxc", "application/vnd.sun.xml.calc");
+    types_map->insert("sxd", "application/vnd.sun.xml.draw");
+    types_map->insert("sxg", "application/vnd.sun.xml.writer.global");
+    types_map->insert("sxi", "application/vnd.sun.xml.impress");
+    types_map->insert("sxm", "application/vnd.sun.xml.math");
+    types_map->insert("sxw", "application/vnd.sun.xml.writer");
+    types_map->insert("t", "application/x-troff");
+    types_map->insert("tar", "application/x-tar");
+    types_map->insert("taz", "application/x-gtar-compressed");
+    types_map->insert("tcl", "text/x-tcl");
+    types_map->insert("tex", "text/x-tex");
+    types_map->insert("texi", "application/x-texinfo");
+    types_map->insert("texinfo", "application/x-texinfo");
+    types_map->insert("text", "text/plain");
+    types_map->insert("tgf", "chemical/x-mdl-tgf");
+    types_map->insert("tgz", "application/x-gtar-compressed");
+    types_map->insert("thmx", "application/vnd.ms-officetheme");
+    types_map->insert("tif", "image/tiff");
+    types_map->insert("tiff", "image/tiff");
+    types_map->insert("tk", "text/x-tcl");
+    types_map->insert("tm", "text/texmacs");
+    types_map->insert("torrent", "application/x-bittorrent");
+    types_map->insert("tr", "application/x-troff");
+    types_map->insert("ts", "video/MP2T");
+    types_map->insert("tsp", "application/dsptype");
+    types_map->insert("tsv", "text/tab-separated-values");
+    types_map->insert("txt", "text/plain");
+    types_map->insert("udeb", "application/x-debian-package");
+    types_map->insert("uls", "text/iuls");
+    types_map->insert("ustar", "application/x-ustar");
+    types_map->insert("val", "chemical/x-ncbi-asn1-binary");
+    types_map->insert("vcd", "application/x-cdlink");
+    types_map->insert("vcf", "text/x-vcard");
+    types_map->insert("vcs", "text/x-vcalendar");
+    types_map->insert("vmd", "chemical/x-vmd");
+    types_map->insert("vms", "chemical/x-vamas-iso14976");
+    types_map->insert("vor", "application/vnd.stardivision.writer");
+    types_map->insert("vrm", "x-world/x-vrml");
+    types_map->insert("vrml", "x-world/x-vrml");
+    types_map->insert("vsd", "application/vnd.visio");
+    types_map->insert("wad", "application/x-doom");
+    types_map->insert("wav", "audio/x-wav");
+    types_map->insert("wax", "audio/x-ms-wax");
+    types_map->insert("wbmp", "image/vnd.wap.wbmp");
+    types_map->insert("wbxml", "application/vnd.wap.wbxml");
+    types_map->insert("webm", "video/webm");
+    types_map->insert("wiz", "application/msword");
+    types_map->insert("wk", "application/x-123");
+    types_map->insert("wm", "video/x-ms-wm");
+    types_map->insert("wma", "audio/x-ms-wma");
+    types_map->insert("wmd", "application/x-ms-wmd");
+    types_map->insert("wml", "text/vnd.wap.wml");
+    types_map->insert("wmlc", "application/vnd.wap.wmlc");
+    types_map->insert("wmls", "text/vnd.wap.wmlscript");
+    types_map->insert("wmlsc", "application/vnd.wap.wmlscriptc");
+    types_map->insert("wmv", "video/x-ms-wmv");
+    types_map->insert("wmx", "video/x-ms-wmx");
+    types_map->insert("wmz", "application/x-ms-wmz");
+    types_map->insert("wp5", "application/vnd.wordperfect5.1");
+    types_map->insert("wpd", "application/vnd.wordperfect");
+    types_map->insert("wrl", "x-world/x-vrml");
+    types_map->insert("wsc", "text/scriptlet");
+    types_map->insert("wsdl", "application/xml");
+    types_map->insert("wvx", "video/x-ms-wvx");
+    types_map->insert("wz", "application/x-wingz");
+    types_map->insert("x3d", "model/x3d+xml");
+    types_map->insert("x3db", "model/x3d+binary");
+    types_map->insert("x3dv", "model/x3d+vrml");
+    types_map->insert("xbm", "image/x-xbitmap");
+    types_map->insert("xcf", "application/x-xcf");
+    types_map->insert("xht", "application/xhtml+xml");
+    types_map->insert("xhtml", "application/xhtml+xml");
+    types_map->insert("xlam", "application/vnd.ms-excel.addin.macroEnabled.12");
+    types_map->insert("xlb", "application/vnd.ms-excel");
+    types_map->insert("xls", "application/vnd.ms-excel");
+    types_map->insert("xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12");
+    types_map->insert("xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12");
+    types_map->insert("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+    types_map->insert("xlt", "application/vnd.ms-excel");
+    types_map->insert("xltm", "application/vnd.ms-excel.template.macroEnabled.12");
+    types_map->insert("xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template");
+    types_map->insert("xml", "application/xml");
+    types_map->insert("xpdl", "application/xml");
+    types_map->insert("xpi", "application/x-xpinstall");
+    types_map->insert("xpm", "image/x-xpixmap");
+    types_map->insert("xsd", "application/xml");
+    types_map->insert("xsl", "application/xml");
+    types_map->insert("xspf", "application/xspf+xml");
+    types_map->insert("xtel", "chemical/x-xtel");
+    types_map->insert("xul", "application/vnd.mozilla.xul+xml");
+    types_map->insert("xwd", "image/x-xwindowdump");
+    types_map->insert("xyz", "chemical/x-xyz");
+    types_map->insert("zip", "application/zip");
+    types_map->insert("zmt", "chemical/x-mopac-input");
+    types_map->insert("~", "application/x-trash");
+}
+
+QString splitPath(const QString& path, int *pos)
+{
+    if (path.isEmpty()) {
+        return "";
+    }
+
+    QString p = QDir::fromNativeSeparators(path);
+    while (p.endsWith('/') && p.size() > 1) {
+        p = p.left(p.size() - 1);
+    }
+    if (p.size() == 1) {
+        return p;
+    }
+
+    *pos = p.lastIndexOf("/");
+    return p;
+}
+
+
+} // namespace
+
+QString mimeTypeFromFileName(const QString& fileName)
+{
+    if (types_map == 0) {
+        init();
+    }
+
+    QString suffix = QFileInfo(fileName).suffix().toLower();
+
+    return types_map->value(suffix);
+}
+
+QString readableNameForFolder(bool readonly)
+{
+    return readonly ? QObject::tr("Readonly Folder") : QObject::tr("Folder");
+}
+
+QString readableNameForFile(const QString& fileName)
+{
+    QString mimetype = mimeTypeFromFileName(fileName);
+
+    if (mimetype.isEmpty()) {
+        return QObject::tr("Document");
+    }
+
+    if (mimetype == "application/pdf") {
+        return QObject::tr("PDF Document");
+    } else if (mimetype.startsWith("image")) {
+        return QObject::tr("Image File");
+    } else if (mimetype.startsWith("text")) {
+        return QObject::tr("Text Document");
+    } else if (mimetype.startsWith("audio")) {
+        return QObject::tr("Audio File");
+    } else if (mimetype.startsWith("video")) {
+        return QObject::tr("Video File");
+    } else if (mimetype.contains("msword") || mimetype.contains("ms-word")) {
+        return QObject::tr("Word Document");
+    } else if (mimetype.contains("mspowerpoint") || mimetype.contains("ms-powerpoint")) {
+        return QObject::tr("PowerPoint Document");
+    } else if (mimetype.contains("msexcel") || mimetype.contains("ms-excel")) {
+        return QObject::tr("Excel Document");
+    } else if (mimetype.contains("openxmlformats-officedocument")) {
+        // see http://stackoverflow.com/questions/4212861/what-is-a-correct-mime-type-for-docx-pptx-etc
+        if (mimetype.contains("wordprocessingml")) {
+            return QObject::tr("Word Document");
+        } else if (mimetype.contains("spreadsheetml")) {
+            return QObject::tr("Excel Document");
+        } else if (mimetype.contains("presentationml")) {
+            return QObject::tr("PowerPoint Document");
+        }
+        // } else if (mimetype.contains("application")) {
+        //     return "binary";
+    }
+
+    return QObject::tr("Document");
+}
+
+QString iconPrefixFromFileName(const QString& fileName)
+{
+    QString mimetype = mimeTypeFromFileName(fileName);
+
+    if (mimetype.isEmpty()) {
+        return "";
+    }
+
+    if (mimetype == "application/pdf") {
+        return "pdf";
+    } else if (mimetype.startsWith("image")) {
+        return "image";
+    } else if (mimetype.startsWith("text")) {
+        return "text";
+    } else if (mimetype.startsWith("audio")) {
+        return "audio";
+    } else if (mimetype.startsWith("video")) {
+        return "video";
+    } else if (mimetype.contains("msword") || mimetype.contains("ms-word")) {
+        return "ms_word";
+    } else if (mimetype.contains("mspowerpoint") || mimetype.contains("ms-powerpoint")) {
+        return "ms_ppt";
+    } else if (mimetype.contains("msexcel") || mimetype.contains("ms-excel")) {
+        return "ms_excel";
+    } else if (mimetype.contains("openxmlformats-officedocument")) {
+        // see http://stackoverflow.com/questions/4212861/what-is-a-correct-mime-type-for-docx-pptx-etc
+        if (mimetype.contains("wordprocessingml")) {
+            return "ms_word";
+        } else if (mimetype.contains("spreadsheetml")) {
+            return "ms_excel";
+        } else if (mimetype.contains("presentationml")) {
+            return "ms_ppt";
+        }
+        // } else if (mimetype.contains("application")) {
+        //     return "binary";
+    } else if (mimetype.contains("7z") || mimetype.contains("rar") ||
+               mimetype.contains("zip") || mimetype.startsWith("application/x-tar")) {
+        return "zip";
+    }
+
+    return "";
+}
+
+
+QString getIconByFileName(const QString& fileName)
+{
+    QString icon = iconPrefixFromFileName(fileName);
+
+    if (icon.isEmpty()) {
+        icon = "unknown";
+    }
+
+    return QString(":/images/files/file_%1.png").arg(icon);
+}
+
+QString getIconByFolder()
+{
+    return QString(":/images/files/file_folder.png");
+}
+
+QString getIconByFileNameV2(const QString& fileName)
+{
+    QString icon = iconPrefixFromFileName(fileName);
+
+    // Use doc icons for text files
+    if (icon == "text") {
+        icon = "ms_word";
+    }
+
+    return QString(":/images/files_v2/file_%1.png").arg(icon.isEmpty() ? "unknown" : icon);
+}
+
+
+QString pathJoin(const QString& a,
+                 const QString& b)
+{
+    QStringList list(b);
+    return pathJoin(a, list);
+}
+
+
+QString pathJoin(const QString& a,
+                 const QString& b,
+                 const QString& c)
+{
+    QStringList list;
+    list << b << c;
+    return pathJoin(a, list);
+}
+
+QString pathJoin(const QString& a,
+                 const QString& b,
+                 const QString& c,
+                 const QString& d)
+{
+    QStringList list;
+    list << b << c << d;
+    return pathJoin(a, list);
+}
+
+QString pathJoin(const QString& a, const QStringList& rest)
+{
+    QString result = a;
+    foreach (const QString& b, rest) {
+        bool resultEndsWithSlash = result.endsWith("/");
+        bool bStartWithSlash = b.startsWith("/");
+        if (resultEndsWithSlash && bStartWithSlash) {
+            result.append(b.right(b.size() - 1));
+        } else if (resultEndsWithSlash || bStartWithSlash) {
+            result.append(b);
+        } else {
+            result.append("/" + b);
+        }
+    }
+
+    return result;
+}
+
+bool createDirIfNotExists(const QString& path)
+{
+    QDir parent_dir = getParentPath(path);
+    return parent_dir.mkpath(getBaseName(path));
+}
+
+QString getParentPath(const QString& path)
+{
+    int pos;
+    QString p = splitPath(path, &pos);
+    if (p.size() <= 1) {
+        return p;
+    }
+
+    if (pos == -1)
+        return "";
+    if (pos == 0)
+        return "/";
+    return p.left(pos);
+}
+
+QString getBaseName(const QString& path)
+{
+    int pos;
+    QString p = splitPath(path, &pos);
+    if (p.size() <= 1) {
+        return p;
+    }
+
+    if (pos == -1) {
+        return p;
+    }
+    return p.mid(pos + 1);
+}
+
+QString expandVars(const QString& origin)
+{
+#ifdef Q_OS_WIN32
+    // expand environment strings
+    QString retval;
+    std::wstring worigin = origin.toStdWString();
+    utils::WBufferArray expanded;
+    expanded.resize(MAX_PATH);
+    DWORD expanded_size = ExpandEnvironmentStringsW(&worigin[0], &expanded[0], MAX_PATH);
+    if (expanded_size > 0) {
+        expanded.resize(expanded_size);
+        if (expanded_size > MAX_PATH)
+            expanded_size = ExpandEnvironmentStringsW(&worigin[0], &expanded[0], expanded_size);
+    }
+    if (expanded_size > 0 && expanded_size == expanded.size()) {
+        retval = QString::fromWCharArray(&expanded[0], expanded_size);
+        // workaround with a bug
+        retval = QString::fromUtf8(retval.toUtf8());
+    } else {
+        retval = origin;
+    }
+#else
+    // TODO implement it
+    QString retval = origin;
+#endif
+    return retval;
+}
+
+QString expandUser(const QString& origin)
+{
+    if (origin.startsWith("~")) {
+        QChar seperator = QDir::separator();
+        int pos = 1;
+        while (pos < origin.size() && origin[pos] != seperator)
+            ++pos;
+        QString homepath;
+        if (pos == 1)
+            homepath = QDir::homePath();
+        else
+            homepath = QFileInfo(QDir::homePath()).dir().filePath(origin.mid(1, pos - 1));
+        return pathJoin(homepath, origin.right(origin.size() - pos));
+    }
+    return origin;
+}
diff --git a/src/utils/file-utils.h b/src/utils/file-utils.h
new file mode 100644 (file)
index 0000000..243f79d
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef SEAFILE_CLIENT_FILE_UTILS_H_
+#define SEAFILE_CLIENT_FILE_UTILS_H_
+
+#include <QString>
+class QStringList;
+
+QString mimeTypeFromFileName(const QString& fileName);
+QString iconPrefixFromFileName(const QString& fileName);
+
+QString getIconByFolder();
+
+QString getIconByFileName(const QString& fileName);
+QString getIconByFileNameV2(const QString& fileName);
+
+QString readableNameForFolder(bool readonly = false);
+QString readableNameForFile(const QString& fileName);
+
+QString getParentPath(const QString& path);
+QString getBaseName(const QString& path);
+
+QString pathJoin(const QString& a, const QString& b);
+QString pathJoin(const QString& a, const QString& b, const QString& c);
+QString pathJoin(const QString& a, const QString& b, const QString& c, const QString& d);
+QString pathJoin(const QString& a, const QStringList& rest);
+
+QString expandVars(const QString& origin);
+QString expandUser(const QString& origin);
+
+bool createDirIfNotExists(const QString& path);
+
+
+#endif // SEAFILE_CLIENT_FILE_UTILS_H_
diff --git a/src/utils/json-utils.cpp b/src/utils/json-utils.cpp
new file mode 100644 (file)
index 0000000..6d38cc7
--- /dev/null
@@ -0,0 +1,47 @@
+#include <jansson.h>
+#include "json-utils.h"
+
+Json::Json(const json_t *root)
+{
+    json_ = root;
+}
+
+QString Json::getString(const char *key) const
+{
+    if (!json_) {
+        return QString();
+    }
+    return QString::fromUtf8(json_string_value(json_object_get(json_, key)));
+}
+
+qint64 Json::getLong(const char *key) const
+{
+    if (!json_) {
+        return 0;
+    }
+    return json_integer_value(json_object_get(json_, key));
+}
+
+bool Json::getBool(const char *key) const
+{
+    if (!json_) {
+        return false;
+    }
+
+    json_t *value = json_object_get(json_, key);
+    if (json_is_false(value))
+        return false;
+    return json_is_true(value) || json_integer_value(value);
+}
+
+Json Json::getObject(const char *key) const
+{
+    if (!json_) {
+        return Json();
+    }
+
+    json_t *object = json_object_get(json_, key);
+    if (json_is_object(object))
+        return Json(object);
+    return Json();
+}
diff --git a/src/utils/json-utils.h b/src/utils/json-utils.h
new file mode 100644 (file)
index 0000000..198a4cf
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SEAFILE_CLIENT_UTILS_JSON_UTILS_H
+
+#include <jansson.h>
+#include <QString>
+
+// A convenient class to access jasson `json_t` struct
+class Json {
+public:
+    Json(const json_t *root = 0);
+
+    QString getString(const char *name) const;
+    qint64 getLong(const char *name) const;
+    bool getBool(const char *name) const;
+    Json getObject(const char *name) const;
+
+private:
+    const json_t *json_;
+};
+
+#endif  // SEAFILE_CLIENT_UTILS_JSON_UTILS_H
diff --git a/src/utils/log.c b/src/utils/log.c
new file mode 100644 (file)
index 0000000..57d8e66
--- /dev/null
@@ -0,0 +1,140 @@
+#include <errno.h>
+#include <time.h>
+#include <glib/gstdio.h>
+
+#include "log.h"
+
+static FILE *logfp;
+
+static GLogLevelFlags applet_log_level;
+
+static int
+checkdir_with_mkdir (const char *dir)
+{
+#if defined(_WIN32)
+    int ret;
+    char *path = g_strdup(dir);
+    char *p = (char *)path + strlen(path) - 1;
+    while (*p == '\\' || *p == '/') *p-- = '\0';
+    ret = g_mkdir_with_parents(path, 0755);
+    g_free (path);
+    return ret;
+#else
+    return g_mkdir_with_parents(dir, 0755);
+#endif
+}
+
+static void
+applet_log (const gchar *log_domain, GLogLevelFlags log_level,
+            const gchar *message, gpointer user_data)
+{
+#define BUFSIZE 1024
+    if (log_level > applet_log_level || message == NULL)
+        return;
+
+    if (log_level & G_LOG_FLAG_FATAL)
+        fputs (message, stderr);
+
+    time_t t;
+    struct tm *tm;
+    char buf[BUFSIZE];
+    size_t len;
+
+    t = time(NULL);
+    tm = localtime(&t);
+    len = strftime (buf, BUFSIZE, "[%x %X]", tm);
+    g_return_if_fail (len < BUFSIZE);
+    fputs (buf, logfp);
+    fputs (message, logfp);
+
+    if (strlen(message) > 0 && message[strlen(message) - 1] != '\n') {
+        fputs("\n", logfp);
+    }
+    fflush (logfp);
+#undef BUFSIZE
+}
+
+static void
+delete_large_log_file(const char* file)
+{
+    GStatBuf log_file_stat_buf;
+    if (g_stat(file, &log_file_stat_buf) != 0) {
+        // Do not warn if errno=2 (file not exist), because during
+        // first run of the client the log files may not be created
+        // yet.
+        if (errno != 2) {
+            g_warning ("Get log file %s stat failed errno=%d.", file, errno);
+        }
+        return;
+    }
+
+    const int delete_threshold = 300 * 1000 * 1000;
+    if (log_file_stat_buf.st_size <= delete_threshold) {
+        return;
+    } else {
+        const char* backup_file_name_postfix = "-old";
+        GString *backup_file = g_string_new(file);
+        g_string_insert(backup_file, backup_file->len - 4, backup_file_name_postfix);
+        // 4 is length of log file postfix ".log"
+        // rename log file "***.log" to "***-old.log"
+        char file_name[4096] = {0};
+        memcpy(file_name, backup_file->str, backup_file->len);
+        if (backup_file) {
+            g_string_free(backup_file, TRUE);
+        }
+
+        if (g_file_test(file_name, G_FILE_TEST_EXISTS)) {
+            if (g_remove(file_name) != 0) {
+                g_warning ("Delete old log file %s failed errno=%d.", file_name, errno);
+                return;
+            } else {
+                g_warning ("Deleted old log file %s.", file_name);
+            }
+        }
+
+        if (g_rename(file, file_name) == 0) {
+            g_warning ("Renamed %s to backup file %s.", file, file_name);
+            return;
+        } else {
+            g_warning ("Rename %s to backup file failed errno=%d.", file, errno);
+            return;
+        }
+    }
+}
+
+int
+applet_log_init (const char *ccnet_dir)
+{
+    char *logdir = g_build_filename (ccnet_dir, "logs", NULL);
+    char *applet_log_file = g_build_filename(logdir, "applet.log", NULL);
+    char *seafile_log_file = g_build_filename(logdir, "seafile.log", NULL);
+
+    if (checkdir_with_mkdir (logdir) < 0) {
+        g_free (logdir);
+        return -1;
+    }
+
+    g_free (logdir);
+
+    delete_large_log_file(applet_log_file);
+    delete_large_log_file(seafile_log_file);
+
+    /* record all log message */
+    applet_log_level = G_LOG_LEVEL_DEBUG;
+
+    if ((logfp = g_fopen (applet_log_file, "a+")) == NULL) {
+        g_warning ("Open file %s failed errno=%d\n", applet_log_file, errno);
+        g_free (applet_log_file);
+        return -1;
+    }
+
+    g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
+                       | G_LOG_FLAG_RECURSION, applet_log, NULL);
+
+    g_log_set_handler ("Ccnet", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
+                       | G_LOG_FLAG_RECURSION, applet_log, NULL);
+
+    g_free (applet_log_file);
+
+    return 0;
+}
diff --git a/src/utils/log.h b/src/utils/log.h
new file mode 100644 (file)
index 0000000..a4e7293
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef SEAFILE_CLIENT_UTILS_LOG_H
+#define SEAFILE_CLIENT_UTILS_LOG_H
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+G_BEGIN_DECLS
+
+int applet_log_init (const char *ccnet_dir);
+
+G_END_DECLS
+
+#endif // SEAFILE_CLIENT_UTILS_LOG_H
diff --git a/src/utils/paint-utils.cpp b/src/utils/paint-utils.cpp
new file mode 100644 (file)
index 0000000..26ad3fe
--- /dev/null
@@ -0,0 +1,88 @@
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "paint-utils.h"
+
+QString fitTextToWidth(const QString& text, const QFont& font, int width)
+{
+    static QString ELLIPSISES = "...";
+
+       QFontMetrics qfm(font);
+       QSize size = qfm.size(0, text);
+       if (size.width() <= width)
+               return text;                            // it fits, so just display it
+
+       // doesn't fit, so we need to truncate and add ellipses
+       QSize sizeElippses = qfm.size(0, ELLIPSISES); // we need to cut short enough to add these
+       QString s = text;
+       while (s.length() > 0)     // never cut shorter than this...
+       {
+               int len = s.length();
+               s = text.left(len-1);
+               size = qfm.size(0, s);
+               if (size.width() <= (width - sizeElippses.width()))
+                       break;              // we are finally short enough
+       }
+
+       return (s + ELLIPSISES);
+}
+
+QFont zoomFont(const QFont& font_in, double ratio)
+{
+    QFont font(font_in);
+
+    if (font.pointSize() > 0) {
+        font.setPointSize((int)(font.pointSize() * ratio));
+    } else {
+        font.setPixelSize((int)(font.pixelSize() * ratio));
+    }
+
+    return font;
+}
+
+QFont changeFontSize(const QFont& font_in, int size)
+{
+    QFont font(font_in);
+
+    font.setPixelSize(size);
+
+    // if (font.pointSize() > 0) {
+    //     font.setPointSize(size);
+    // } else {
+    //     font.setPixelSize(size);
+    // }
+
+    return font;
+}
+
+int textWidthInFont(const QString text, const QFont& font)
+{
+       QFontMetrics qfm(font);
+       QSize size = qfm.size(0, text);
+
+    return size.width();
+}
+
+int textHeightInFont(const QString text, const QFont& font)
+{
+       QFontMetrics qfm(font);
+       QSize size = qfm.size(Qt::TextSingleLine, text);
+
+    return size.height();
+}
+
+// it might change when screen moves
+// QIcon::addFile will add a "@2x" file if it exists.
+double globalDevicePixelRatio()
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    return qApp->devicePixelRatio();
+#else
+    return 1.0;
+#endif
+}
diff --git a/src/utils/paint-utils.h b/src/utils/paint-utils.h
new file mode 100644 (file)
index 0000000..d4a61c2
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SEAFILE_CLIENT_PAINT_UTILS_H_
+#define SEAFILE_CLIENT_PAINT_UTILS_H_
+
+#include <QFont>
+#include "utils-mac.h"
+#include <QIcon>
+
+QString fitTextToWidth(const QString& text, const QFont& font, int width);
+
+QFont zoomFont(const QFont& font_in, double ratio);
+
+QFont changeFontSize(const QFont& font_in, int size);
+
+int textWidthInFont(const QString text, const QFont& font);
+
+int textHeightInFont(const QString text, const QFont& font);
+
+double globalDevicePixelRatio();
+
+#endif // SEAFILE_CLIENT_PAINT_UTILS_H_
diff --git a/src/utils/process-linux.cpp b/src/utils/process-linux.cpp
new file mode 100644 (file)
index 0000000..87f4b95
--- /dev/null
@@ -0,0 +1,123 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <glib.h>
+
+#include "process.h"
+#if !defined(PATH_MAX)
+#define PATH_MAX 512
+#endif
+namespace {
+const int kBUFFSIZE = 4096;
+}
+
+static int
+find_process_in_dirent(struct dirent *dir, const char *process_name)
+{
+    char path[PATH_MAX];
+    /* first construct a path like /proc/123/exe */
+    if (snprintf (path, PATH_MAX, "/proc/%s/exe", dir->d_name) < 0) {
+        return -1;
+    }
+
+    char buf[kBUFFSIZE];
+    /* get the full path of exe */
+    ssize_t l = readlink(path, buf, kBUFFSIZE - 1);
+
+    if (l < 0)
+        return -1;
+    buf[l] = '\0';
+
+    /* get the base name of exe */
+    char *base = g_path_get_basename(buf);
+    int ret = strcmp(base, process_name);
+    g_free(base);
+
+    if (ret == 0)
+        return atoi(dir->d_name);
+    else
+        return -1;
+}
+
+/* read the /proc fs to determine whether some process is running */
+int process_is_running (const char *process_name)
+{
+    DIR *proc_dir = opendir("/proc");
+    if (!proc_dir) {
+        fprintf (stderr, "failed to open /proc/ dir\n");
+        return FALSE;
+    }
+
+    struct dirent *subdir = NULL;
+    while ((subdir = readdir(proc_dir))) {
+        char first = subdir->d_name[0];
+        /* /proc/[1-9][0-9]* */
+        if (first > '9' || first < '1')
+            continue;
+        int pid = find_process_in_dirent(subdir, process_name);
+        if (pid > 0) {
+            closedir(proc_dir);
+            return TRUE;
+        }
+    }
+
+    closedir(proc_dir);
+    return FALSE;
+}
+
+void shutdown_process (const char *name)
+{
+    DIR *proc_dir = opendir("/proc");
+    if (!proc_dir) {
+        fprintf (stderr, "failed to open /proc/ dir\n");
+        return;
+    }
+
+    struct dirent *subdir = NULL;
+    pid_t current_pid = getpid();
+    while ((subdir = readdir(proc_dir))) {
+        char first = subdir->d_name[0];
+        /* /proc/[1-9][0-9]* */
+        if (first > '9' || first < '1')
+            continue;
+        int pid = find_process_in_dirent(subdir, name);
+        // don't kill itself!
+        if (pid > 0 && pid != current_pid) {
+            kill (pid, SIGKILL);
+        }
+    }
+
+    closedir(proc_dir);
+}
+
+int count_process(const char *process_name)
+{
+    int count = 0;
+    DIR *proc_dir = opendir("/proc");
+    if (!proc_dir) {
+        g_warning ("failed to open /proc/ :%s\n", strerror(errno));
+        return FALSE;
+    }
+
+    struct dirent *subdir = NULL;
+    while ((subdir = readdir(proc_dir))) {
+        char first = subdir->d_name[0];
+        /* /proc/[1-9][0-9]* */
+        if (first > '9' || first < '1')
+            continue;
+        if (find_process_in_dirent(subdir, process_name) > 0) {
+            count++;
+        }
+    }
+
+    closedir (proc_dir);
+    return count;
+}
+
+int count_process(const char *name, uint64_t *pid)
+{
+    return count_process(name);
+}
diff --git a/src/utils/process-mac.cpp b/src/utils/process-mac.cpp
new file mode 100644 (file)
index 0000000..44e667c
--- /dev/null
@@ -0,0 +1,168 @@
+#include "process.h"
+
+#include <sys/sysctl.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <glib.h>
+
+typedef struct kinfo_proc kinfo_proc;
+
+static int GetBSDProcessList (kinfo_proc **procList, size_t *procCount)
+{
+    int                 err;
+    kinfo_proc *        result;
+    bool                done;
+    static const int    name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+    // Declaring name as const requires us to cast it when passing it to
+    // sysctl because the prototype doesn't include the const modifier.
+    size_t              length;
+
+    assert ( procList != NULL);
+    assert (*procList == NULL);
+    assert (procCount != NULL);
+
+    *procCount = 0;
+
+    // We start by calling sysctl with result == NULL and length == 0.
+    // That will succeed, and set length to the appropriate length.
+    // We then allocate a buffer of that size and call sysctl again
+    // with that buffer.  If that succeeds, we're done.  If that fails
+    // with ENOMEM, we have to throw away our buffer and loop.  Note
+    // that the loop causes use to call sysctl with NULL again; this
+    // is necessary because the ENOMEM failure case sets length to
+    // the amount of data returned, not the amount of data that
+    // could have been returned.
+
+    result = NULL;
+    done = false;
+    do {
+        assert (result == NULL);
+        // Call sysctl with a NULL buffer.
+
+        length = 0;
+        err = sysctl ((int *) name, (sizeof(name) / sizeof(*name)) - 1,
+                     NULL, &length,
+                     NULL, 0);
+        if (err == -1) {
+            err = errno;
+        }
+
+        // Allocate an appropriately sized buffer based on the results
+        // from the previous call.
+
+        if (err == 0) {
+            result = (kinfo_proc *)malloc (length);
+            if (result == NULL) {
+                err = ENOMEM;
+            }
+        }
+
+        // Call sysctl again with the new buffer.  If we get an ENOMEM
+        // error, toss away our buffer and start again.
+
+        if (err == 0) {
+            err = sysctl ((int *) name, (sizeof(name) / sizeof(*name)) - 1,
+                         result, &length,
+                         NULL, 0);
+            if (err == -1) {
+                err = errno;
+            }
+            if (err == 0) {
+                done = true;
+            } else if (err == ENOMEM) {
+                assert(result != NULL);
+                free (result);
+                result = NULL;
+                err = 0;
+            }
+        }
+    } while (err == 0 && ! done);
+
+    // Clean up and establish post conditions.
+
+    if (err != 0 && result != NULL) {
+        free (result);
+        result = NULL;
+    }
+    *procList = result;
+    if (err == 0) {
+        *procCount = length / sizeof(kinfo_proc);
+    }
+
+    assert ( (err == 0) == (*procList != NULL) );
+
+    return err;
+}
+
+static int getBSDProcessPid (const char *name, int except_pid)
+{
+    int pid = 0;
+    struct kinfo_proc *mylist = NULL;
+    size_t mycount = 0;
+    GetBSDProcessList (&mylist, &mycount);
+    for (size_t k = 0; k < mycount; k++) {
+        kinfo_proc *proc =  &mylist[k];
+        if (proc->kp_proc.p_pid != except_pid
+            && strcmp (proc->kp_proc.p_comm, name) == 0
+            && proc->kp_eproc.e_pcred.p_ruid == getuid()){
+            pid = proc->kp_proc.p_pid;
+            break;
+        }
+    }
+    free (mylist);
+    return pid;
+}
+
+int process_is_running (const char *name)
+{
+    int pid = getBSDProcessPid (name, getpid ());
+    if (pid)
+        return true;
+    return false;
+}
+
+
+void shutdown_process (const char *name)
+{
+    struct kinfo_proc *mylist = NULL;
+    size_t mycount = 0;
+    pid_t current_pid = getpid();
+    GetBSDProcessList (&mylist, &mycount);
+    for (size_t k = 0; k < mycount; k++) {
+        kinfo_proc *proc =  &mylist[k];
+        if (strcmp (proc->kp_proc.p_comm, name) == 0 &&
+            proc->kp_proc.p_pid != current_pid &&
+            proc->kp_eproc.e_pcred.p_ruid == getuid()) {
+            // printf ("seaf-daemon pid = %d\n", proc->kp_proc.p_pid);
+            kill (proc->kp_proc.p_pid, SIGKILL);
+        }
+    }
+    free (mylist);
+}
+
+int count_process(const char *process_name)
+{
+    int count = 0;
+    struct kinfo_proc *mylist = NULL;
+    size_t mycount = 0;
+    GetBSDProcessList (&mylist, &mycount);
+    for (size_t k = 0; k < mycount; k++) {
+        kinfo_proc *proc =  &mylist[k];
+        if (strcmp (proc->kp_proc.p_comm, process_name) == 0
+            && proc->kp_eproc.e_pcred.p_ruid == getuid()){
+            count++;
+        }
+    }
+    free (mylist);
+    return count;
+}
+
+int count_process(const char *name, uint64_t *pid)
+{
+    return count_process(name);
+}
diff --git a/src/utils/process-win.cpp b/src/utils/process-win.cpp
new file mode 100644 (file)
index 0000000..19c5a3e
--- /dev/null
@@ -0,0 +1,185 @@
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#include <windows.h>
+#include <psapi.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+
+#include <QList>
+
+#include "process.h"
+
+namespace {
+
+/// always ignore current process
+HANDLE
+get_process_handle (const char *process_name_in)
+{
+    char name[256];
+    if (strstr(process_name_in, ".exe")) {
+        snprintf (name, sizeof(name), "%s", process_name_in);
+    } else {
+        snprintf (name, sizeof(name), "%s.exe", process_name_in);
+    }
+
+    DWORD aProcesses[1024], cbNeeded, cProcesses;
+
+    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
+        return NULL;
+
+    /* Calculate how many process identifiers were returned. */
+    cProcesses = cbNeeded / sizeof(DWORD);
+
+    HANDLE hProcess;
+    DWORD hCurrentProcessId = GetCurrentProcessId();
+    unsigned int i;
+    DWORD length;
+
+    for (i = 0; i < cProcesses; i++) {
+        if(aProcesses[i] == 0 || aProcesses[i] == hCurrentProcessId)
+            continue;
+        hProcess = OpenProcess (PROCESS_QUERY_INFORMATION |
+                                PROCESS_TERMINATE |
+                                PROCESS_VM_READ |
+                                SYNCHRONIZE , FALSE, aProcesses[i]);
+        if (!hProcess)
+            continue;
+
+        char process_name[4096] = {0};
+
+        // The GetProcessImageFileName function returns the path in device form, rather than drive letters
+        // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683196%28v=vs.85%29.aspx
+        // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683217%28v=vs.85%29.aspx
+        if (!(length = GetProcessImageFileName(hProcess, process_name, sizeof(process_name)))) {
+            CloseHandle(hProcess);
+            continue;
+        }
+        char *basename = strrchr(process_name, '\\');
+        length -= (basename - process_name);
+
+        // if basename doesn't start with `\` or not mached
+        if (*basename != '\\' ||
+            strncasecmp(name, ++basename, length) != 0) {
+            CloseHandle(hProcess);
+            continue;
+        }
+
+        return hProcess;
+    }
+    /* Not found */
+    return NULL;
+}
+
+int
+win32_kill_process (const char *process_name)
+{
+    HANDLE proc_handle = get_process_handle(process_name);
+
+    if (proc_handle) {
+        TerminateProcess(proc_handle, 0);
+        CloseHandle(proc_handle);
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+
+} // namespace
+
+int
+process_is_running (const char *process_name)
+{
+    HANDLE proc_handle = get_process_handle(process_name);
+
+    if (proc_handle) {
+        CloseHandle(proc_handle);
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+void shutdown_process (const char *name)
+{
+    while (win32_kill_process(name) >= 0) ;
+}
+
+// Return the number of processes with the given executable name, and also
+// return the list of pids of them (except the current process, if it mathces)
+static int count_process_internal (const char *process_name_in, QList<uint64_t> *pids)
+{
+    char name[MAX_PATH];
+    DWORD aProcesses[1024], cbNeeded, cProcesses;
+    HANDLE hProcess;
+    DWORD length;
+    int count = 0;
+    DWORD i;
+    DWORD hCurrentProcessId = GetCurrentProcessId();
+
+    if (strstr(process_name_in, ".exe")) {
+        snprintf (name, sizeof(name), "%s", process_name_in);
+    } else {
+        snprintf (name, sizeof(name), "%s.exe", process_name_in);
+    }
+
+    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
+        return 0;
+    }
+
+    /* Calculate how many process identifiers were returned. */
+    cProcesses = cbNeeded / sizeof(DWORD);
+
+    for (i = 0; i < cProcesses; i++) {
+        if(aProcesses[i] == 0)
+            continue;
+        hProcess = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
+        if (!hProcess) {
+            continue;
+        }
+
+        char process_name[4096] = {0};
+        if (!(length = GetProcessImageFileName(hProcess, process_name, sizeof(process_name)))) {
+            CloseHandle(hProcess);
+            continue;
+        }
+        char *basename = strrchr(process_name, '\\');
+        length -= (basename - process_name);
+
+        // if basename doesn't start with `\` or not mached
+        if (*basename != '\\' ||
+            strncasecmp(name, ++basename, length) != 0) {
+            CloseHandle(hProcess);
+            continue;
+        }
+
+        if (pids && aProcesses[i] != hCurrentProcessId) {
+            pids->append(aProcesses[i]);
+        }
+        count++;
+        CloseHandle(hProcess);
+    }
+
+    return count;
+}
+
+int count_process (const char *process_name_in) {
+    return count_process_internal(process_name_in, nullptr);
+}
+
+int count_process(const char *name, uint64_t *pid)
+{
+    QList<uint64_t> pids;
+    int ret = count_process_internal(name, &pids);
+    if (pid && !pids.isEmpty()) {
+        *pid = pids[0];
+    }
+    return ret;
+}
diff --git a/src/utils/process.h b/src/utils/process.h
new file mode 100644 (file)
index 0000000..c5304e0
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef SEAFILE_CLIENT_UTILS_PROCESS_H
+#define SEAFILE_CLIENT_UTILS_PROCESS_H
+
+#include <stdint.h>
+
+// process related functions
+int process_is_running (const char *process_name);
+
+void shutdown_process (const char *name);
+
+// Return the number of processes whose executable name is `name`.
+int count_process(const char *name);
+
+// Same as count_process(name), but also return the pid of the first matched
+// non-self process.
+int count_process(const char *name, uint64_t *pid);
+
+#endif // SEAFILE_CLIENT_UTILS_PROCESS_H
diff --git a/src/utils/registry.cpp b/src/utils/registry.cpp
new file mode 100644 (file)
index 0000000..7857d14
--- /dev/null
@@ -0,0 +1,347 @@
+#include <windows.h>
+#include <shlwapi.h>
+#include <vector>
+
+#include "utils/stl.h"
+#include "utils/utils.h"
+
+
+#include "registry.h"
+
+namespace {
+
+LONG openKey(HKEY root, const QString& path, HKEY *p_key, REGSAM samDesired = KEY_ALL_ACCESS)
+{
+    LONG result;
+    result = RegOpenKeyExW(root,
+                           path.toStdWString().c_str(),
+                           0L,
+                           samDesired,
+                           p_key);
+
+    return result;
+}
+
+QString softwareSeafile()
+{
+    return QString("SOFTWARE\\%1").arg(getBrand());
+}
+
+} // namespace
+
+RegElement::RegElement(const HKEY& root, const QString& path,
+                       const QString& name, const QString& value, bool expand)
+    : root_(root),
+      path_(path),
+      name_(name),
+      string_value_(value),
+      dword_value_(0),
+      type_(expand ? REG_EXPAND_SZ : REG_SZ)
+{
+}
+
+RegElement::RegElement(const HKEY& root, const QString& path,
+                       const QString& name, DWORD value)
+    : root_(root),
+      path_(path),
+      name_(name),
+      string_value_(""),
+      dword_value_(value),
+      type_(REG_DWORD)
+{
+}
+
+int RegElement::openParentKey(HKEY *pKey)
+{
+    DWORD disp;
+    HRESULT result;
+
+    result = RegCreateKeyExW (root_,
+                              path_.toStdWString().c_str(),
+                              0, NULL,
+                              REG_OPTION_NON_VOLATILE,
+                              KEY_WRITE | KEY_WOW64_64KEY,
+                              NULL,
+                              pKey,
+                              &disp);
+
+    if (result != ERROR_SUCCESS) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int RegElement::add()
+{
+    HKEY parent_key;
+    DWORD value_len;
+    LONG result;
+
+    if (openParentKey(&parent_key) < 0) {
+        return -1;
+    }
+
+    if (type_ == REG_SZ || type_ == REG_EXPAND_SZ) {
+        // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms724923(v=vs.85).aspx
+        value_len = sizeof(wchar_t) * (string_value_.toStdWString().length() + 1);
+        result = RegSetValueExW (parent_key,
+                                 name_.toStdWString().c_str(),
+                                 0, REG_SZ,
+                                 (const BYTE *)(string_value_.toStdWString().c_str()),
+                                 value_len);
+    } else {
+        value_len = sizeof(dword_value_);
+        result = RegSetValueExW (parent_key,
+                                 name_.toStdWString().c_str(),
+                                 0, REG_DWORD,
+                                 (const BYTE *)&dword_value_,
+                                 value_len);
+    }
+
+    if (result != ERROR_SUCCESS) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int RegElement::removeRegKey(HKEY root, const QString& path, const QString& subkey)
+{
+    HKEY hKey;
+    LONG result = RegOpenKeyExW(root,
+                                path.toStdWString().c_str(),
+                                0L,
+                                KEY_ALL_ACCESS,
+                                &hKey);
+
+    if (result != ERROR_SUCCESS) {
+        return -1;
+    }
+
+    result = SHDeleteKeyW(hKey, subkey.toStdWString().c_str());
+    if (result != ERROR_SUCCESS) {
+        return -1;
+    }
+
+    return 0;
+}
+
+bool RegElement::exists()
+{
+    HKEY parent_key;
+    LONG result = openKey(root_, path_, &parent_key, KEY_READ);
+    if (result != ERROR_SUCCESS) {
+        return false;
+    }
+
+    result = RegQueryValueExW (parent_key,
+                               name_.toStdWString().c_str(),
+                               NULL,             /* reserved */
+                               NULL,             /* output type */
+                               NULL,             /* output data */
+                               NULL);            /* output length */
+
+    RegCloseKey(parent_key);
+    if (result != ERROR_SUCCESS) {
+        return false;
+    }
+
+    return true;
+}
+
+void RegElement::read()
+{
+    string_value_.clear();
+    dword_value_ = 0;
+    HKEY parent_key;
+    LONG result = openKey(root_, path_, &parent_key, KEY_READ);
+    if (result != ERROR_SUCCESS) {
+        return;
+    }
+    const std::wstring std_name = name_.toStdWString();
+
+    DWORD len;
+    // get value size
+    result = RegQueryValueExW (parent_key,
+                               std_name.c_str(),
+                               NULL,             /* reserved */
+                               &type_,           /* output type */
+                               NULL,             /* output data */
+                               &len);            /* output length */
+    if (result != ERROR_SUCCESS) {
+        RegCloseKey(parent_key);
+        return;
+    }
+    // get value
+#ifndef UTILS_CXX11_MODE
+    std::vector<wchar_t> buf;
+#else
+    utils::WBufferArray buf;
+#endif
+    buf.resize(len);
+    result = RegQueryValueExW (parent_key,
+                               std_name.c_str(),
+                               NULL,             /* reserved */
+                               &type_,           /* output type */
+                               (LPBYTE)&buf[0],  /* output data */
+                               &len);            /* output length */
+    buf.resize(len);
+    if (result != ERROR_SUCCESS) {
+        RegCloseKey(parent_key);
+        return;
+    }
+
+    switch (type_) {
+        case REG_EXPAND_SZ:
+        case REG_SZ:
+            {
+                // expand environment strings
+                wchar_t expanded_buf[MAX_PATH];
+                DWORD size = ExpandEnvironmentStringsW(&buf[0], expanded_buf, MAX_PATH);
+                if (size == 0 || size > MAX_PATH)
+                    string_value_ = QString::fromWCharArray(&buf[0], buf.size());
+                else
+                    string_value_ = QString::fromWCharArray(expanded_buf, size);
+            }
+            break;
+        case REG_NONE:
+        case REG_BINARY:
+            string_value_ = QString::fromWCharArray(&buf[0], buf.size() / 2);
+            break;
+        case REG_DWORD_BIG_ENDIAN:
+        case REG_DWORD:
+            if (buf.size() != sizeof(int))
+                return;
+            memcpy((char*)&dword_value_, buf.data(), sizeof(int));
+            break;
+        case REG_QWORD: {
+            if (buf.size() != sizeof(int))
+                return;
+            qint64 value;
+            memcpy((char*)&value, buf.data(), sizeof(int));
+            dword_value_ = (int)value;
+            break;
+        }
+        case REG_MULTI_SZ:
+        default:
+          break;
+    }
+
+    RegCloseKey(parent_key);
+
+    // workaround with a bug
+    string_value_ = QString::fromUtf8(string_value_.toUtf8());
+
+    return;
+}
+
+void RegElement::remove()
+{
+    HKEY parent_key;
+    LONG result = openKey(root_, path_, &parent_key, KEY_ALL_ACCESS);
+    if (result != ERROR_SUCCESS) {
+        return;
+    }
+    result = RegDeleteValueW (parent_key, name_.toStdWString().c_str());
+    RegCloseKey(parent_key);
+}
+
+QVariant RegElement::value() const
+{
+    if (type_ == REG_SZ || type_ == REG_EXPAND_SZ
+        || type_ == REG_NONE || type_ == REG_BINARY) {
+        return string_value_;
+    } else {
+        return int(dword_value_);
+    }
+}
+
+int RegElement::getIntValue(HKEY root,
+                            const QString& path,
+                            const QString& name,
+                            bool *exists,
+                            int default_val)
+{
+    RegElement reg(root, path, name, "");
+    if (!reg.exists()) {
+        if (exists) {
+            *exists = false;
+        }
+        return default_val;
+    }
+    if (exists) {
+        *exists = true;
+    }
+    reg.read();
+
+    if (!reg.stringValue().isEmpty())
+        return reg.stringValue().toInt();
+
+    return reg.dwordValue();
+}
+
+int RegElement::getPreconfigureIntValue(const QString& name)
+{
+    bool exists;
+    int ret = getIntValue(
+        HKEY_CURRENT_USER, softwareSeafile(), name, &exists);
+    if (exists) {
+        return ret;
+    }
+
+    return RegElement::getIntValue(
+        HKEY_LOCAL_MACHINE, softwareSeafile(), name);
+}
+
+QString RegElement::getStringValue(HKEY root,
+                                   const QString& path,
+                                   const QString& name,
+                                   bool *exists,
+                                   QString default_val)
+{
+    RegElement reg(root, path, name, "");
+    if (!reg.exists()) {
+        if (exists) {
+            *exists = false;
+        }
+        return default_val;
+    }
+    if (exists) {
+        *exists = true;
+    }
+    reg.read();
+    return reg.stringValue();
+}
+
+QString RegElement::getPreconfigureStringValue(const QString& name)
+{
+    bool exists;
+    QString ret = getStringValue(
+        HKEY_CURRENT_USER, softwareSeafile(), name, &exists);
+    if (exists) {
+        return ret;
+    }
+
+    return RegElement::getStringValue(
+        HKEY_LOCAL_MACHINE, softwareSeafile(), name);
+}
+
+QVariant RegElement::getPreconfigureValue(const QString& name)
+{
+    QVariant v = getValue(HKEY_CURRENT_USER, softwareSeafile(), name);
+    return v.isNull() ? getValue(HKEY_LOCAL_MACHINE, softwareSeafile(), name) : v;
+}
+
+QVariant RegElement::getValue(HKEY root,
+                              const QString& path,
+                              const QString& name)
+{
+    RegElement reg(root, path, name, "");
+    if (!reg.exists()) {
+        return QVariant();
+    }
+    reg.read();
+
+    return reg.value();
+}
diff --git a/src/utils/registry.h b/src/utils/registry.h
new file mode 100644 (file)
index 0000000..6cb4e1d
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef SEAFILE_CLIENT_UTILS_REGISTRY_H
+#define SEAFILE_CLIENT_UTILS_REGISTRY_H
+
+#include <QString>
+#include <QVariant>
+#include <windows.h>
+
+
+#ifndef KEY_WOW64_64KEY
+#define KEY_WOW64_64KEY 0x0100
+#endif
+
+#ifndef KEY_WOW64_32KEY
+#define KEY_WOW64_32KEY 0x0200
+#endif
+
+/**
+ * Windows Registry Element
+ */
+class RegElement {
+public:
+    static void removeRegKey(const QString& key);
+
+    RegElement(const HKEY& root,
+               const QString& path,
+               const QString& name,
+               const QString& value,
+               bool expand=false);
+
+    RegElement(const HKEY& root,
+               const QString& path,
+               const QString& name,
+               DWORD value);
+
+    int add();
+    void read();
+    void remove();
+    bool exists();
+
+    const HKEY& root() const { return root_; }
+    const QString& path() const { return path_; }
+    const QString& name() const { return name_; }
+    const QString& stringValue() const { return string_value_; }
+    DWORD dwordValue() const { return dword_value_; }
+    QVariant value() const;
+
+public:
+    static int removeRegKey(HKEY root, const QString& path, const QString& subkey);
+
+    static int getIntValue(HKEY root, const QString& path, const QString& name, bool *exists=NULL, int default_val=0);
+    static QString getStringValue(HKEY root, const QString& path, const QString& name, bool *exists=NULL, QString default_val=QString());
+    static int getPreconfigureIntValue(const QString& name);
+    static QString getPreconfigureStringValue(const QString& name);
+
+    static QVariant getPreconfigureValue(const QString& name);
+    static QVariant getValue(HKEY root, const QString& path, const QString& name);
+
+private:
+    int openParentKey(HKEY *pKey);
+
+    HKEY root_;
+    QString path_;
+    QString name_;
+    QString string_value_;
+    DWORD dword_value_;
+    DWORD type_;
+};
+
+#endif // SEAFILE_CLIENT_UTILS_REGISTRY_H
diff --git a/src/utils/rsa.cpp b/src/utils/rsa.cpp
new file mode 100644 (file)
index 0000000..350b790
--- /dev/null
@@ -0,0 +1,188 @@
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/err.h>
+
+#include <glib.h>
+#include <cstring>
+
+#include "rsa.h"
+#include "utils.h"
+
+namespace {
+
+/* Forward compatibility functions if libssl < 1.1.0. */
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+{
+   /* If the fields n and e in r are NULL, the corresponding input
+    * parameters MUST be non-NULL for n and e.  d may be
+    * left NULL (in case only the public key is used).
+    */
+   if ((r->n == NULL && n == NULL)
+       || (r->e == NULL && e == NULL))
+       return 0;
+   if (n != NULL) {
+       BN_free(r->n);
+       r->n = n;
+   }
+   if (e != NULL) {
+       BN_free(r->e);
+       r->e = e;
+   }
+   if (d != NULL) {
+       BN_free(r->d);
+       r->d = d;
+   }
+   return 1;
+}
+
+void RSA_get0_key(const RSA *r,
+                 const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+   if (n != NULL)
+       *n = r->n;
+   if (e != NULL)
+       *e = r->e;
+   if (d != NULL)
+       *d = r->d;
+}
+
+#endif
+
+int calculate_sha1 (unsigned char *sha1, const char *msg)
+{
+    SHA_CTX c;
+
+    SHA1_Init(&c);
+    SHA1_Update(&c, msg, strlen(msg));
+    SHA1_Final(sha1, &c);
+    return 0;
+}
+
+void
+rawdata_to_hex (const unsigned char *rawdata, char *hex_str, int n_bytes)
+{
+    static const char hex[] = "0123456789abcdef";
+    int i;
+
+    for (i = 0; i < n_bytes; i++) {
+        unsigned int val = *rawdata++;
+        *hex_str++ = hex[val >> 4];
+        *hex_str++ = hex[val & 0xf];
+    }
+    *hex_str = '\0';
+}
+
+#define sha1_to_hex(sha1, hex) rawdata_to_hex((sha1), (hex), 20)
+
+GString* public_key_to_gstring(const RSA *rsa)
+{
+    GString *buf = g_string_new(NULL);
+    unsigned char *temp;
+    char *coded;
+    const BIGNUM *n, *e;
+
+    RSA_get0_key (rsa, &n, &e, NULL);
+    gsize len = BN_num_bytes(n);
+    temp = (unsigned char *)malloc(len);
+    BN_bn2bin(n, temp);
+    coded = g_base64_encode(temp, len);
+    g_string_append (buf, coded);
+    g_string_append_c (buf, ' ');
+    g_free(coded);
+
+    len = BN_num_bytes(e);
+    temp = (unsigned char*)realloc(temp, len);
+    BN_bn2bin(e, temp);
+    coded = g_base64_encode(temp, len);
+    g_string_append (buf, coded);
+    g_free(coded);
+
+    free(temp);
+
+    return buf;
+}
+
+/*
+RSA* public_key_from_string(char *str)
+{
+    char *p;
+    unsigned char *num;
+    gsize len;
+    if (!str)
+        return NULL;
+
+    if ( !(p = strchr(str, ' ')) )
+        return NULL;
+    *p = '\0';
+
+    RSA *key = RSA_new();
+
+    num = g_base64_decode(str, &len);
+    key->n = BN_bin2bn(num, len, NULL);
+    if (!key->n)
+        goto err;
+    g_free(num);
+
+    num = g_base64_decode(p+1, &len);
+    key->e = BN_bin2bn(num, len, NULL);
+    if (!key->e)
+        goto err;
+    g_free(num);
+
+    *p = ' ';
+    return key;
+err:
+    *p = ' ';
+    RSA_free (key);
+    g_free(num);
+    return NULL;
+}
+*/
+
+} // namespace
+
+
+RSA*
+private_key_to_pub(RSA *priv)
+{
+    RSA *pub = RSA_new();
+    const BIGNUM *n, *e;
+
+    RSA_get0_key (priv, &n, &e, NULL);
+    RSA_set0_key (pub, BN_dup(n), BN_dup(e), NULL);
+
+    return pub;
+}
+
+
+char *
+id_from_pubkey (RSA *pubkey)
+{
+    GString *buf;
+    unsigned char sha1[20];
+    char *id = (char *)g_malloc(41);
+
+    buf = public_key_to_gstring (pubkey);
+    calculate_sha1 (sha1, buf->str);
+    sha1_to_hex (sha1, id);
+    g_string_free (buf, TRUE);
+
+    return id;
+}
+
+RSA *
+generate_private_key(int bits)
+{
+    RSA *priv = RSA_new ();
+    BIGNUM *e = BN_new ();
+
+    BN_set_word (e, 35);
+    RSA_generate_key_ex (priv, bits, e, NULL);
+
+    BN_free (e);
+    return priv;
+}
diff --git a/src/utils/rsa.h b/src/utils/rsa.h
new file mode 100644 (file)
index 0000000..e0d8fe4
--- /dev/null
@@ -0,0 +1,14 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef SEAFILE_CLIENT_RSA_H
+#define SEAFILE_CLIENT_RSA_H
+
+#include <openssl/rsa.h>
+
+RSA* private_key_to_pub(RSA *priv);
+
+RSA* generate_private_key(int bits);
+
+char *id_from_pubkey (RSA *pubkey);
+
+#endif
diff --git a/src/utils/singleton.h b/src/utils/singleton.h
new file mode 100644 (file)
index 0000000..65fbda6
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SEAFILE_CLIENT_UTILS_SINGLETON_H
+#define SEAFILE_CLIENT_UTILS_SINGLETON_H
+
+/**
+ * This macro helps conveniently define singleton classes. Usage:
+ *
+ * // foo.h
+ * #include "utils/singleton.h"
+ * class Foo {
+ *     SINGLETON_DEFINE(Foo)
+ * private:
+ *     Foo()
+ *     ...
+ * }
+
+ * // foo.cpp
+ * #include "foo.h"
+ * SINGLETON_IMPL(Foo)
+*/
+
+#define SINGLETON_DEFINE(CLASS) \
+    public: \
+    static CLASS *instance(); \
+    private: \
+    static CLASS *singleton_;                   \
+
+#define SINGLETON_IMPL(CLASS) \
+    CLASS* CLASS::singleton_; \
+    CLASS* CLASS::instance() { \
+        if (singleton_ == NULL) { \
+            static CLASS instance; \
+            singleton_ = &instance; \
+        } \
+        return singleton_; \
+    }
+
+#endif // SEAFILE_CLIENT_UTILS_SINGLETON_H
diff --git a/src/utils/stl.cpp b/src/utils/stl.cpp
new file mode 100644 (file)
index 0000000..655f0e0
--- /dev/null
@@ -0,0 +1,16 @@
+#include "stl.h"
+
+namespace utils {
+
+template class BasicBufferArray<char>;
+template class BasicBufferArray<wchar_t>;
+
+template <>
+inline void swap(BasicBufferArray<char> &LHS,
+                 BasicBufferArray<char> &RHS) UTILS_CXX11_NOEXCEPT;
+
+template <>
+inline void swap(BasicBufferArray<wchar_t> &LHS,
+                 BasicBufferArray<wchar_t> &RHS) UTILS_CXX11_NOEXCEPT;
+
+} // namespace utils
diff --git a/src/utils/stl.h b/src/utils/stl.h
new file mode 100644 (file)
index 0000000..55d43de
--- /dev/null
@@ -0,0 +1,142 @@
+#ifndef SEAFILE_CLIENT_UTILS_STL_H_
+#define SEAFILE_CLIENT_UTILS_STL_H_
+
+#include <utility>
+#include <cassert>
+#include <string>
+#include <cstring>
+#include <cwchar>
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
+#define UTILS_CXX11_MODE
+#define UTILS_CXX11_DELETE = delete
+#define UTILS_CXX11_NOEXCEPT noexcept
+#else
+#define UTILS_CXX11_DELETE
+#define UTILS_CXX11_NOEXCEPT
+#endif
+
+namespace utils {
+template <typename T = char> class BasicBufferArray {
+    typedef T char_type;
+    char_type *data_;
+    size_t size_;
+    size_t capacity_;
+
+    BasicBufferArray(const BasicBufferArray &buffer) UTILS_CXX11_DELETE;
+    BasicBufferArray &
+    operator=(const BasicBufferArray &buffer) UTILS_CXX11_DELETE;
+
+  public:
+    void swap(BasicBufferArray &RHS) UTILS_CXX11_NOEXCEPT {
+        std::swap(data_, RHS.data_);
+        std::swap(size_, RHS.size_);
+        std::swap(capacity_, RHS.capacity_);
+    }
+#ifdef UTILS_CXX11_MODE
+    BasicBufferArray(BasicBufferArray &&RHS) UTILS_CXX11_NOEXCEPT
+        : data_(RHS.data_),
+          size_(RHS.size_),
+          capacity_(RHS.capacity_) {
+        RHS.data_ = NULL;
+        RHS.size_ = 0;
+        RHS.capacity_ = 0;
+    }
+    BasicBufferArray &operator=(BasicBufferArray &&RHS) UTILS_CXX11_NOEXCEPT {
+        std::swap(data_, RHS.data_);
+        std::swap(size_, RHS.size_);
+        std::swap(capacity_, RHS.capacity_);
+        return *this;
+    }
+#endif // UTILS_CXX11_MODE
+
+    ~BasicBufferArray() {
+        if (capacity_ && data_)
+            delete[] data_;
+    }
+    BasicBufferArray() : data_(NULL), size_(0), capacity_(0){};
+    BasicBufferArray(const char_type *buffer) {
+        const char_type *end = buffer;
+        while (*end++ != '\0')
+            ;
+        capacity_ = size_ = end - buffer;
+
+        data_ = new char_type[size_];
+        assert(data_ != NULL);
+        memcpy(data_, buffer, size_ * sizeof(char_type));
+    }
+    BasicBufferArray(const char_type *buffer, size_t size) {
+        data_ = new char_type[size];
+        assert(data_ != NULL);
+        capacity_ = size_ = size;
+        memcpy(data_, buffer, size * sizeof(char_type));
+    }
+    BasicBufferArray(const std::basic_string<char_type> &string) {
+        if (string.size() == 0) {
+            data_ = NULL;
+            capacity_ = size_ = 0;
+            return;
+        }
+        capacity_ = size_ = string.size() + 1;
+        data_ = new char_type[size_];
+        assert(data_ != NULL);
+        memcpy(data_, string.data(), size_ * sizeof(char_type));
+        data_[size_ - 1] = '\0';
+    }
+
+    char_type *data() { return data_; }
+    const char_type *data() const { return data_; }
+
+    size_t size() const { return size_; }
+    size_t capacity() const { return capacity_; }
+    void shrink_to_fit() {
+        if (size_ == capacity_)
+            return;
+        char_type *new_data = NULL;
+        if (size_ != 0) {
+            char_type *new_data = new char_type[size_];
+            assert(new_data != NULL);
+            memcpy(new_data, data_, size_ * sizeof(char_type));
+        }
+        delete[] data_;
+        capacity_ = size_;
+        data_ = new_data;
+    }
+    void reserve(size_t new_capacity) {
+        if (new_capacity <= capacity_)
+            return;
+        char_type *new_data = new char_type[new_capacity];
+        assert(new_data != NULL);
+        if (data_) {
+            memcpy(new_data, data_, size_ * sizeof(char_type));
+            delete[] data_;
+        }
+        capacity_ = new_capacity;
+        data_ = new_data;
+    }
+    void resize(size_t new_size) {
+        if (new_size <= capacity_) {
+            size_ = new_size;
+            return;
+        }
+        reserve(new_size);
+        size_ = new_size;
+    };
+
+    char_type &operator[](size_t pos) { return *(data() + pos); }
+
+    const char_type &operator[](size_t pos) const { return *(data() + pos); }
+};
+
+template <typename T>
+inline void swap(BasicBufferArray<T> &LHS,
+                 BasicBufferArray<T> &RHS) UTILS_CXX11_NOEXCEPT {
+    LHS.swap(RHS);
+}
+
+extern template class BasicBufferArray<char>;
+extern template class BasicBufferArray<wchar_t>;
+typedef BasicBufferArray<char> BufferArray;
+typedef BasicBufferArray<wchar_t> WBufferArray;
+
+} // namespace utils
+#endif // SEAFILE_CLIENT_UTILS_STL_H_
diff --git a/src/utils/translate-commit-desc.cpp b/src/utils/translate-commit-desc.cpp
new file mode 100644 (file)
index 0000000..49a7456
--- /dev/null
@@ -0,0 +1,208 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <QHash>
+#include <QObject>
+#include <QApplication>
+#include <QRegExp>
+#include <QStringList>
+
+#include "utils/utils.h"
+#include "translate-commit-desc.h"
+#include "utils/file-utils.h"
+
+namespace {
+
+//const char *kTranslateContext = "MessageListener";
+
+QHash<QString, QString> *verbsMap = NULL;
+
+QHash<QString, QString>*
+getVerbsMap()
+{
+    if (!verbsMap) {
+        verbsMap = new QHash<QString, QString>;
+        verbsMap->insert("Added", QObject::tr("Added"));
+        verbsMap->insert("Added or modified", QObject::tr("Added or modified"));
+        verbsMap->insert("Deleted", QObject::tr("Deleted"));
+        verbsMap->insert("Removed", QObject::tr("Removed"));
+        verbsMap->insert("Modified", QObject::tr("Modified"));
+        verbsMap->insert("Renamed", QObject::tr("Renamed"));
+        verbsMap->insert("Moved", QObject::tr("Moved"));
+        verbsMap->insert("Added directory", QObject::tr("Added directory"));
+        verbsMap->insert("Removed directory", QObject::tr("Removed directory"));
+        verbsMap->insert("Renamed directory", QObject::tr("Renamed directory"));
+        verbsMap->insert("Moved directory", QObject::tr("Moved directory"));
+    }
+
+    return verbsMap;
+}
+
+QString translateLine(const QString line)
+{
+    QString operations = ((QStringList)getVerbsMap()->keys()).join("|");
+    QString pattern = QString("(%1) \"(.*)\"\\s?(and ([0-9]+) more (files|directories))?").arg(operations);
+
+    QRegExp regex(pattern);
+
+    if (regex.indexIn(line) < 0) {
+        return line;
+    }
+
+    QString op = regex.cap(1);
+    QString file_name = regex.cap(2);
+    QString has_more = regex.cap(3);
+    QString n_more = regex.cap(4);
+    QString more_type = regex.cap(5);
+
+    QString op_trans = getVerbsMap()->value(op, op);
+
+    QString type, ret;
+    if (has_more.length() > 0) {
+        if (more_type == "files") {
+            type = QObject::tr("files");
+        } else {
+            type = QObject::tr("directories");
+        }
+
+        QString more = QObject::tr("and %1 more").arg(n_more);
+        ret = QString("%1 \"%2\" %3 %4.").arg(op_trans).arg(file_name).arg(more).arg(type);
+    } else {
+        ret = QString("%1 \"%2\".").arg(op_trans).arg(file_name);
+    }
+
+    return ret;
+}
+
+} // namespace
+
+
+QString
+translateCommitDesc(const QString& input)
+{
+    QString value = input;
+    if (value.startsWith("Reverted repo")) {
+        value.replace("repo", "library");
+    }
+
+    if (value.startsWith("Reverted library")) {
+        return value.replace("Reverted library to status at", QObject::tr("Reverted library to status at"));
+    } else if (value.startsWith("Reverted file")) {
+        QRegExp regex("Reverted file \"(.*)\" to status at (.*)");
+
+        if (regex.indexIn(value) >= 0) {
+            QString name = regex.cap(1);
+            QString time = regex.cap(2);
+            return QObject::tr("Reverted file \"%1\" to status at %2.").arg(name).arg(time);
+        }
+
+    } else if (value.startsWith("Recovered deleted directory")) {
+        return value.replace("Recovered deleted directory", QObject::tr("Recovered deleted directory"));
+    } else if (value.startsWith("Changed library")) {
+        return value.replace("Changed library name or description", QObject::tr("Changed library name or description"));
+    } else if (value.startsWith("Merged") || value.startsWith("Auto merge")) {
+        return QObject::tr("Auto merge by %1 system").arg(getBrand());
+    }
+
+    QStringList lines = value.split("\n");
+    QStringList out;
+
+    for (int i = 0; i < lines.size(); i++) {
+        out << translateLine(lines.at(i));
+    }
+
+    return out.join("\n");
+}
+
+// path: the path of activity file or folder
+// file_name: the name of activity file item
+// repo_name: the name of activity repository item
+// obj_type: the object of activity item include (file, path, repository)
+// op_type: the operation type of obj_name
+// old_repo_name: when rename repo the origin repo name
+// old_path: when rename path the origin  path name
+// old_name: when rename file the origin file name
+// clean_trash_days: the days since clean the trash
+// out_obj_desc: the description of obj_name
+// out out_op_desc: the description of opt_type
+void
+translateCommitDescV2(const QString& path, const QString& file_name, const QString& repo_name,
+                      const QString& obj_type, const QString& op_type, const QString& old_repo_name,
+                      const QString& old_path, const QString& old_name, int clean_trash_days,
+                      QString *out_obj_desc, QString *out_op_desc)
+{
+    if (obj_type == "repo") {
+        if (op_type == "create") {
+            *out_op_desc = QObject::tr("Created library");
+        } else if (op_type == "rename") {
+            *out_op_desc = QObject::tr("Renamed library");
+        } else if (op_type == "delete") {
+            *out_op_desc = QObject::tr("Deleted library");
+            *out_obj_desc = repo_name;
+        } else if (op_type == "recover") {
+            *out_op_desc = QObject::tr("Restored library");
+        } else if (op_type == "clean_up_trash") {
+            if (clean_trash_days == 0) {
+                *out_op_desc = QObject::tr("Removed all items from trash");
+            } else {
+                *out_op_desc = QObject::tr("Removed items older than days %1 from trash").arg(clean_trash_days);
+            }
+        }
+
+        if (op_type == "rename") {
+            *out_obj_desc = old_repo_name + " => " + repo_name;
+        } else {
+            *out_obj_desc = repo_name;
+        }
+
+    } else if (obj_type == "draft") {
+            *out_op_desc = QObject::tr("Published draft");
+            *out_obj_desc = file_name;
+    } else if (obj_type == "file") {
+        if (op_type == "create") {
+            if (file_name.endsWith("(draft).md")) {
+                *out_op_desc = QObject::tr("Created draft");
+            } else {
+                *out_op_desc = QObject::tr("Created file");
+            }
+        } else if (op_type == "rename") {
+            *out_op_desc = QObject::tr("Renamed file");
+        } else if (op_type == "delete") {
+            if (file_name.endsWith("(draft).md")) {
+                *out_op_desc = QObject::tr("Deleted draft");
+            } else {
+                *out_op_desc = QObject::tr("Deleted file");
+            }
+        } else if (op_type == "recover") {
+            *out_op_desc = QObject::tr("Restored file");
+        } else if (op_type == "move") {
+            *out_op_desc = QObject::tr("Moved file");
+        } else if (op_type == "edit") {
+            *out_op_desc = QObject::tr("Updated file");
+        }
+
+        if (op_type == "rename") {
+            *out_obj_desc = old_name + " => " + file_name;
+        } else {
+            *out_obj_desc = file_name;
+        }
+
+    } else { //dir
+        if (op_type == "create") {
+            *out_op_desc = QObject::tr("Created folder");
+         } else if (op_type == "rename") {
+            *out_op_desc = QObject::tr("Renamed folder");
+         } else if (op_type == "delete") {
+            *out_op_desc = QObject::tr("Deleted folder");
+         } else if (op_type == "recover") {
+            *out_op_desc = QObject::tr("Restored folder");
+         } else if (op_type == "move") {
+            *out_op_desc = QObject::tr("Moved folder");
+        }
+        if (op_type == "rename") {
+            *out_obj_desc = old_path + " => " + path;
+        } else {
+            *out_obj_desc = path;
+        }
+    }
+
+}
diff --git a/src/utils/translate-commit-desc.h b/src/utils/translate-commit-desc.h
new file mode 100644 (file)
index 0000000..47a4f60
--- /dev/null
@@ -0,0 +1,16 @@
+
+#ifndef SEAFILE_CELINT_TRANSLATE_COMMIT_DESC_H
+#define SEAFILE_CELINT_TRANSLATE_COMMIT_DESC_H
+
+#include <QString>
+
+QString
+translateCommitDesc (const QString& input);
+
+void
+translateCommitDescV2(const QString& path, const QString& file_name, const QString& repo_name,
+                      const QString& obj_type, const QString& op_type, const QString& old_repo_name,
+                      const QString& old_path, const QString& old_name, int clean_trash_days,
+                      QString *out_obj_desc, QString *out_op_desc);
+
+#endif  // SEAFILE_CELINT_TRANSLATE_COMMIT_DESC_H
diff --git a/src/utils/uninstall-helpers.cpp b/src/utils/uninstall-helpers.cpp
new file mode 100644 (file)
index 0000000..9d7ebfb
--- /dev/null
@@ -0,0 +1,250 @@
+extern "C" {
+#include <searpc-client.h>
+
+#include <searpc.h>
+#include <seafile/seafile.h>
+#include <seafile/seafile-object.h>
+
+}
+
+#include <QtGlobal>
+
+#if defined(Q_OS_WIN32)
+#include <windows.h>
+#include <shellapi.h>
+#else
+#include <memory>
+#include <fts.h>
+#include <errno.h>
+#include <unistd.h>
+#endif
+
+#include <glib.h>
+
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+#include <QMessageBox>
+#include <QIcon>
+#include <QMainWindow>
+
+#include "utils/utils.h"
+#include "settings-mgr.h"
+#include "ui/uninstall-helper-dialog.h"
+#include "rpc/rpc-server.h"
+
+#if defined(Q_OS_WIN32)
+#include "utils/registry.h"
+#endif
+
+#include "uninstall-helpers.h"
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+const char *kPreconfigureKeepConfigWhenUninstall = "PreconfigureKeepConfigWhenUninstall";
+#endif
+
+#if !defined(Q_OS_WIN32)
+int posix_rmdir(const QString &root)
+{
+    if (!QFileInfo(root).exists()) {
+        qWarning("dir %s doesn't exists", toCStr(root));
+        return -1;
+    }
+
+    std::unique_ptr<char[]> root_ptr(strdup(toCStr(root)));
+
+    char *paths[] = {root_ptr.get(), NULL};
+
+    // Using `FTS_PHYSICAL` here because we need `FTSENT` for the
+    // symbolic link in the directory and not the target it links to.
+    FTS *tree = fts_open(paths, (FTS_NOCHDIR | FTS_PHYSICAL), NULL);
+    if (tree == NULL) {
+        qWarning("failed to fts_open: %s", strerror(errno));
+        return -1;
+    }
+
+    FTSENT *node;
+    while ((node = fts_read(tree)) != NULL) {
+        // printf ("%s: fts_info = %d\n", node->fts_path, (int)(node->fts_info));
+        switch (node->fts_info) {
+            case FTS_DP:
+                // qWarning("removing directory %s", node->fts_path);
+                if (rmdir(node->fts_path) < 0 && errno != ENOENT) {
+                    qWarning("failed to remove dir %s", node->fts_path);
+                }
+                break;
+            // `FTS_DEFAULT` would include any file type which is not
+            // explicitly described by any of the other `fts_info` values.
+            case FTS_DEFAULT:
+            case FTS_F:
+            case FTS_SL:
+            // `FTS_SLNONE` should never be the case as we don't set
+            // `FTS_COMFOLLOW` or `FTS_LOGICAL`. Adding here for completion.
+            case FTS_SLNONE:
+                // qWarning("removing file %s", node->fts_path);
+                if (unlink(node->fts_path) < 0 && errno != ENOENT) {
+                    qWarning("failed to remove file %s", node->fts_path);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (errno != 0) {
+        fts_close(tree);
+        return -1;
+    }
+
+    if (fts_close(tree) < 0) {
+        return -1;
+    }
+    return 0;
+}
+#endif
+
+} // namespace
+
+int delete_dir_recursively(const QString& path_in)
+{
+    qWarning ("removing folder %s\n", toCStr(path_in));
+#if defined(Q_OS_WIN32)
+    const QString path = QDir::toNativeSeparators(QDir::cleanPath(path_in));
+    if (path.length() <= 3) {
+        // avoid errornous delete drives like C:/ D:/ E:/
+        return -1;
+    }
+
+    int len = path.length();
+
+    wchar_t *wpath = new wchar_t[len + 2];
+
+    wcscpy(wpath, path.toStdWString().c_str());
+    wpath[len + 1] = L'\0';
+
+    SHFILEOPSTRUCTW fileop;
+    fileop.hwnd   = NULL;       // no status display
+    fileop.wFunc  = FO_DELETE;  // delete operation
+    fileop.pFrom  = wpath; // source file name as double null terminated string
+    fileop.pTo    = NULL;         // no destination needed
+    fileop.fFlags = FOF_NOCONFIRMATION|FOF_SILENT; // do not prompt the user
+
+    fileop.fAnyOperationsAborted = FALSE;
+    fileop.lpszProgressTitle     = NULL;
+    fileop.hNameMappings         = NULL;
+
+    int ret = SHFileOperationW(&fileop);
+
+    delete []wpath;
+
+    if (ret == 0) {
+        return 0;
+    } else {
+        return -1;
+    }
+    return 0;
+#else
+    return posix_rmdir(path_in);
+#endif
+}
+
+
+int get_ccnet_dir(QString *ret)
+{
+    QString path = defaultCcnetDir();
+
+    if (!QFileInfo(path).exists()) {
+        return -1;
+    }
+
+    *ret = path;
+    return 0;
+}
+
+int get_seafile_data_dir(const QString& ccnet_dir, QString *ret)
+{
+    QFile seafile_ini(QDir(ccnet_dir).filePath("seafile.ini"));
+    if (!seafile_ini.exists()) {
+        return -1;
+    }
+
+    if (!seafile_ini.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        return -1;
+    }
+
+    QTextStream input(&seafile_ini);
+    input.setCodec("UTF-8");
+
+    if (input.atEnd()) {
+        return -1;
+    }
+
+    QString path = input.readLine();
+    if (!QFileInfo(QDir(path).filePath("repo.db")).exists()) {
+        return -1;
+    }
+
+    *ret = path;
+    return 0;
+}
+
+void do_ping()
+{
+    SeafileAppletRpcServer::Client *client = SeafileAppletRpcServer::getClient();
+    if (!client->connect()) {
+        printf ("failed to connect to applet rpc server\n");
+        return;
+    }
+    QString resp;
+    if (client->sendPingCommand(&resp)) {
+        printf ("response: %s\n", toCStr(resp));
+    } else {
+        printf ("failed to send ping command\n");
+    }
+}
+
+void do_stop()
+{
+    SeafileAppletRpcServer::Client *client = SeafileAppletRpcServer::getClient();
+    if (!client->connect()) {
+        printf ("failed to connect to applet rpc server\n");
+        return;
+    }
+    if (client->sendExitCommand()) {
+        printf ("exit command: success\n");
+    } else {
+        printf ("exit command: failed\n");
+    }
+}
+
+#if defined(Q_OS_WIN32)
+int hasPreconfigureKeepConfigWhenUninstall()
+{
+    return RegElement::getPreconfigureIntValue(kPreconfigureKeepConfigWhenUninstall);
+}
+#endif
+
+void do_remove_user_data()
+{
+    do_stop();
+    set_seafile_auto_start(false);
+
+#if defined(Q_OS_WIN32)
+    if (hasPreconfigureKeepConfigWhenUninstall()) {
+        return;
+    }
+#endif
+
+    SettingsManager::removeAllSettings();
+
+    UninstallHelperDialog *dialog = new UninstallHelperDialog;
+
+    dialog->show();
+    dialog->raise();
+    dialog->activateWindow();
+
+    qApp->exec();
+}
diff --git a/src/utils/uninstall-helpers.h b/src/utils/uninstall-helpers.h
new file mode 100644 (file)
index 0000000..eb18a38
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SEAFILE_CLIENT_UTILS_UNINSTALL_HELPERS_H
+#define SEAFILE_CLIENT_UTILS_UNINSTALL_HELPERS_H
+
+#include <QString>
+
+void do_ping();
+/**
+ * Stop running seafile client.
+ */
+void do_stop();
+
+/**
+ * Remove ccnet and seafile-data
+ */
+void do_remove_user_data();
+
+int get_ccnet_dir(QString *ret);
+int get_seafile_data_dir(const QString& ccnet_dir, QString *ret);
+int delete_dir_recursively(const QString& path_in);
+
+#endif // SEAFILE_CLIENT_UTILS_UNINSTALL_HELPERS_H
diff --git a/src/utils/utils-mac.h b/src/utils/utils-mac.h
new file mode 100644 (file)
index 0000000..6b1b60e
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef SEAFILE_CLIENT_UTILS_MAC_H_
+#define SEAFILE_CLIENT_UTILS_MAC_H_
+#include <QtGlobal>
+#ifdef Q_OS_MAC
+#include <QString>
+#include <vector>
+#include <QByteArray>
+
+typedef void DarkModeChangedCallback(bool value);
+
+namespace utils {
+namespace mac {
+// a list for os x versions https://support.apple.com/en-us/HT201260
+// release        major minor patch
+// Yosemite       10    10    ?
+// Mavericks      10    9     ?
+// Mountain Lion  10    8     ?
+// Lion           10    7     ?
+void getSystemVersion(unsigned *major, unsigned *minor, unsigned *patch);
+bool isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch);
+bool isOSXYosemiteOrGreater();
+bool isOSXMavericksOrGreater();
+bool isOSXMountainLionOrGreater();
+bool isOSXLionOrGreater();
+
+void setDockIconStyle(bool hidden);
+void orderFrontRegardless(unsigned long long win_id, bool force = false);
+bool get_auto_start();
+void set_auto_start(bool enabled);
+void copyTextToPasteboard(const QString &text);
+
+bool is_darkmode();
+void set_darkmode_watcher(DarkModeChangedCallback *cb);
+
+QString fix_file_id_url(const QString &path);
+
+QString mainBundlePath();
+
+// load the missing part of ca certificates
+std::vector<QByteArray> getSystemCaCertificates();
+
+} // namespace mac
+} // namespace utils
+#else
+namespace utils {
+namespace mac {
+inline bool isOSXYosemiteOrGreater() { return false; }
+inline bool isOSXMavericksOrGreater() { return false; }
+inline bool isOSXMountainLionOrGreater() { return false; }
+inline bool isOSXLionOrGreater() { return false; }
+} // namespace mac
+} // namespace utils
+#endif /* Q_OS_MAC */
+
+#endif /* SEAFILE_CLIENT_UTILS_MAC_H_ */
diff --git a/src/utils/utils-mac.mm b/src/utils/utils-mac.mm
new file mode 100644 (file)
index 0000000..768aeb2
--- /dev/null
@@ -0,0 +1,497 @@
+#include "utils-mac.h"
+
+#include <AvailabilityMacros.h>
+#import <Cocoa/Cocoa.h>
+#import <Security/Security.h>
+
+#include <openssl/asn1.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+
+#if !__has_feature(objc_arc)
+#error this file must be built with ARC support
+#endif
+
+// borrowed from AvailabilityMacros.h
+#ifndef MAC_OS_X_VERSION_10_10
+#define MAC_OS_X_VERSION_10_10      101000
+#endif
+#ifndef MAC_OS_X_VERSION_10_9
+#define MAC_OS_X_VERSION_10_9         1090
+#endif
+#ifndef MAC_OS_X_VERSION_10_8
+#define MAC_OS_X_VERSION_10_8         1080
+#endif
+#ifndef MAC_OS_X_VERSION_10_7
+#define MAC_OS_X_VERSION_10_7         1070
+#endif
+
+// ****************************************************************************
+// utils::mac::getSystemVersion
+// utils::mac::isAtLeastSystemVersion
+// ****************************************************************************
+
+namespace utils {
+namespace mac {
+namespace {
+unsigned osver_major = 0;
+unsigned osver_minor = 0;
+unsigned osver_patch = 0;
+inline bool isInitializedSystemVersion() { return osver_major != 0; }
+inline void initializeSystemVersion() {
+    if (isInitializedSystemVersion())
+        return;
+#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
+    NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
+    osver_major = version.majorVersion;
+    osver_minor = version.minorVersion;
+    osver_patch = version.patchVersion;
+#else
+    NSString *versionString = [[NSProcessInfo processInfo] operatingSystemVersionString];
+    NSArray *array = [versionString componentsSeparatedByString:@" "];
+    if (array.count < 2) {
+        osver_major = 10;
+        osver_minor = 7;
+        osver_patch = 0;
+        return;
+    }
+
+    NSArray *versionArray = [[array objectAtIndex:1] componentsSeparatedByString:@"."];
+    if (versionArray.count < 2) {
+        osver_major = 10;
+        osver_minor = 7;
+        osver_patch = 0;
+        return;
+    }
+    osver_major = [[versionArray objectAtIndex:0] intValue];
+    osver_minor = [[versionArray objectAtIndex:1] intValue];
+    if (versionArray.count > 2) {
+        osver_patch = [[versionArray objectAtIndex:2] intValue];
+    }
+#endif
+}
+
+inline bool _isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
+{
+    initializeSystemVersion();
+#define OSVER_TO_NUM(major, minor, patch) ((major << 20) + (minor << 10) + (patch))
+#define OSVER_SYS() OSVER_TO_NUM(osver_major, osver_minor, osver_patch)
+    if (OSVER_SYS() < OSVER_TO_NUM(major, minor, patch)) {
+        return false;
+    }
+#undef OSVER_SYS
+#undef OSVER_TO_NUM
+    return true;
+}
+// compile statically
+template<unsigned major, unsigned minor, unsigned patch>
+inline bool isAtLeastSystemVersion()
+{
+    return _isAtLeastSystemVersion(major, minor, patch);
+}
+} // anonymous namespace
+
+void getSystemVersion(unsigned *major, unsigned *minor, unsigned *patch) {
+    initializeSystemVersion();
+    *major = osver_major;
+    *minor = osver_minor;
+    *patch = osver_patch;
+}
+
+bool isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
+{
+    return _isAtLeastSystemVersion(major, minor, patch);
+}
+
+bool isOSXYosemiteOrGreater()
+{
+    return isAtLeastSystemVersion<10, 10, 0>();
+}
+
+bool isOSXMavericksOrGreater()
+{
+    return isAtLeastSystemVersion<10, 9, 0>();
+}
+
+bool isOSXMountainLionOrGreater()
+{
+    return isAtLeastSystemVersion<10, 8, 0>();
+}
+
+bool isOSXLionOrGreater()
+{
+    return isAtLeastSystemVersion<10, 7, 0>();
+}
+
+} // namespace mac
+} // namesapce utils
+
+// ****************************************************************************
+// darkmode related
+// ****************************************************************************
+@interface DarkmodeHelper : NSObject
+- (void)getDarkMode;
+@end
+
+static bool darkMode = false;
+static DarkModeChangedCallback *darkModeWatcher = NULL;
+@implementation DarkmodeHelper
+- (id) init {
+    self = [super init];
+
+    // darkmode is available version >= 10.10
+    if (utils::mac::isOSXYosemiteOrGreater()) {
+        [self getDarkMode];
+
+        [[NSDistributedNotificationCenter defaultCenter] addObserver:self
+        selector:@selector(darkModeChanged:)
+        name:@"AppleInterfaceThemeChangedNotification" object:nil];
+    }
+    return self;
+}
+
+- (void)darkModeChanged:(NSNotification *)aNotification
+{
+    bool oldDarkMode = darkMode;
+    [self getDarkMode];
+
+    if (oldDarkMode != darkMode && darkModeWatcher) {
+        darkModeWatcher(darkMode);
+    }
+}
+
+- (void)getDarkMode {
+    NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];
+    id style = [dict objectForKey:@"AppleInterfaceStyle"];
+    darkMode = ( style && [style isKindOfClass:[NSString class]] && NSOrderedSame == [style caseInsensitiveCompare:@"dark"]);
+}
+@end
+
+// ****************************************************************************
+// others
+// ****************************************************************************
+namespace utils {
+namespace mac {
+
+// another solution: hide dock icon when mainwindows is closed and show when
+// mainwindows is shown
+// http://stackoverflow.com/questions/16994331/multiprocessing-qt-app-how-can-i-limit-it-to-a-single-icon-in-the-macos-x-dock
+void setDockIconStyle(bool hidden) {
+    ProcessSerialNumber psn = { 0, kCurrentProcess };
+    OSStatus err;
+    if (hidden) {
+        // kProcessTransformToBackgroundApplication is not support on OSX 10.7 and before
+        // kProcessTransformToUIElementApplication is used for better fit when possible
+        unsigned major;
+        unsigned minor;
+        unsigned patch;
+        getSystemVersion(&major, &minor, &patch);
+        if (major == 10 && minor == 7)
+            err = TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
+        else
+            err = TransformProcessType(&psn, kProcessTransformToUIElementApplication);
+    } else {
+        // kProcessTransformToForegroundApplication is supported on OSX 10.6 or later
+        err = TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+    }
+    if (err != noErr)
+        qWarning("setDockIconStyle %s failure, status code: %d\n", (hidden ? "hidden" : "show"), err);
+}
+
+void orderFrontRegardless(unsigned long long win_id, bool force) {
+    NSView __weak *widget =  (__bridge NSView*)(void*)win_id;
+    NSWindow *window = [widget window];
+    if(force || [window isVisible])
+        [window performSelector:@selector(orderFrontRegardless) withObject:nil afterDelay:0.05];
+}
+
+// https://bugreports.qt-project.org/browse/QTBUG-40449 is fixed in QT 5.4.1
+// TODO remove this and related code once qt 5.4.1 is widely used
+QString fix_file_id_url(const QString &path) {
+    if (!path.startsWith("/.file/id="))
+        return path;
+    const QString url = "file://" + path;
+    NSString *fileIdURL = [NSString stringWithCString:url.toUtf8().data()
+                                    encoding:NSUTF8StringEncoding];
+    NSURL *goodURL = [[NSURL URLWithString:fileIdURL] filePathURL];
+    NSString *filePath = goodURL.path; // readonly
+
+    QString retval = QString::fromUtf8([filePath UTF8String],
+                                       [filePath lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
+    return retval;
+}
+
+// original idea come from growl framework
+// http://growl.info/about
+bool get_auto_start()
+{
+    NSURL *itemURL = [[NSBundle mainBundle] bundleURL];
+    CFURLRef URLToToggle = (__bridge CFURLRef)itemURL;
+
+    bool found = false;
+
+    LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+    if (loginItems) {
+        UInt32 seed = 0U;
+        CFArrayRef currentLoginItems = LSSharedFileListCopySnapshot(loginItems,
+                                                                    &seed);
+        const CFIndex count = CFArrayGetCount(currentLoginItems);
+        for (CFIndex idx = 0; idx < count; ++idx) {
+            LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(currentLoginItems, idx);
+            CFURLRef outURL = NULL;
+
+            const UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
+#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
+            outURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, /*outError*/ NULL);
+            if (outURL == NULL) {
+#else
+            OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &outURL, /*outRef*/ NULL);
+            if (err != noErr || outURL == NULL) {
+#endif
+                if (outURL)
+                    CFRelease(outURL);
+                continue;
+            }
+            found = CFEqual(outURL, URLToToggle);
+            CFRelease(outURL);
+
+            if (found)
+                break;
+        }
+        CFRelease(currentLoginItems);
+        CFRelease(loginItems);
+    }
+    return found;
+}
+
+void set_auto_start(bool enabled)
+{
+    NSURL *itemURL = [[NSBundle mainBundle] bundleURL];
+    CFURLRef URLToToggle = (__bridge CFURLRef)itemURL;
+
+    LSSharedFileListRef loginItems = LSSharedFileListCreate(kCFAllocatorDefault, kLSSharedFileListSessionLoginItems, /*options*/ NULL);
+    if (loginItems) {
+        UInt32 seed = 0U;
+        Boolean found;
+        LSSharedFileListItemRef existingItem = NULL;
+
+        CFArrayRef currentLoginItems = LSSharedFileListCopySnapshot(loginItems,
+                                                                    &seed);
+        const CFIndex count = CFArrayGetCount(currentLoginItems);
+        for (CFIndex idx = 0; idx < count; ++idx) {
+            LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(currentLoginItems, idx);
+            CFURLRef outURL = NULL;
+
+            const UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
+#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
+            outURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, /*outError*/ NULL);
+            if (outURL == NULL) {
+#else
+            OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &outURL, /*outRef*/ NULL);
+            if (err != noErr || outURL == NULL) {
+#endif
+                if (outURL)
+                    CFRelease(outURL);
+                continue;
+            }
+            found = CFEqual(outURL, URLToToggle);
+            CFRelease(outURL);
+
+            if (found) {
+                existingItem = item;
+                break;
+            }
+        }
+
+        if (enabled && !found) {
+            NSString *displayName = @"Seafile Client";
+            IconRef icon = NULL;
+            FSRef ref;
+            // TODO: replace the deprecated CFURLGetFSRef
+            Boolean gotRef = CFURLGetFSRef(URLToToggle, &ref);
+            if (gotRef) {
+                OSStatus err = GetIconRefFromFileInfo(
+                    &ref,
+                    /*fileNameLength*/ 0,
+                    /*fileName*/ NULL, kFSCatInfoNone,
+                    /*catalogInfo*/ NULL, kIconServicesNormalUsageFlag, &icon,
+                    /*outLabel*/ NULL);
+                if (err != noErr) {
+                    if (icon)
+                        CFRelease(icon);
+                    icon = NULL;
+                }
+            }
+
+            LSSharedFileListItemRef newItem = LSSharedFileListInsertItemURL(
+                loginItems, kLSSharedFileListItemBeforeFirst,
+                (__bridge CFStringRef)displayName, icon, URLToToggle,
+                /*propertiesToSet*/ NULL, /*propertiesToClear*/ NULL);
+            if (newItem)
+                CFRelease(newItem);
+            if (icon)
+                CFRelease(icon);
+        } else if (!enabled && found) {
+            LSSharedFileListItemRemove(loginItems, existingItem);
+        }
+
+        CFRelease(currentLoginItems);
+        CFRelease(loginItems);
+    }
+}
+
+bool is_darkmode() {
+    static DarkmodeHelper *helper = nil;
+    if (!helper) {
+        helper = [[DarkmodeHelper alloc] init];
+    }
+    return darkMode;
+}
+void set_darkmode_watcher(DarkModeChangedCallback *cb) {
+    darkModeWatcher = cb;
+}
+
+void copyTextToPasteboard(const QString &text) {
+    NSString *text_data = [NSString stringWithUTF8String:text.toUtf8().data()];
+    NSPasteboard *paste_board = [NSPasteboard generalPasteboard];
+    [paste_board clearContents];
+    [paste_board declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil];
+    [paste_board writeObjects:@[text_data]];
+}
+
+QString mainBundlePath() {
+    NSURL *url = [[NSBundle mainBundle] bundleURL];
+    return [[url path] UTF8String];
+}
+
+static inline bool isSslPolicy(SecPolicyRef policy) {
+    bool is_ssl = false;
+    CFDictionaryRef properties = NULL;
+    if (!policy)
+        return false;
+    if ((properties = SecPolicyCopyProperties(policy)) == NULL)
+        return false;
+    CFTypeRef value = NULL;
+    if (CFDictionaryGetValueIfPresent(properties, kSecPolicyOid,
+                                      (const void **)&value) &&
+        CFEqual(value, kSecPolicyAppleSSL))
+        is_ssl = true;
+
+    ;
+    CFRelease(properties);
+    return is_ssl;
+}
+
+static bool isCertificateDistrustedByUser(SecCertificateRef cert,
+                                          SecTrustSettingsDomain domain) {
+    CFArrayRef trustSettings;
+    // On return, an array of CFDictionary objects specifying the trust settings
+    // for the certificate
+    OSStatus status = SecTrustSettingsCopyTrustSettings(cert, domain, &trustSettings);
+    if (status != errSecSuccess)
+        return false;
+
+    bool distrusted = false;
+
+    CFNumberRef result;
+    SecTrustSettingsResult result_val;
+    CFIndex size = CFArrayGetCount(trustSettings);
+    for (CFIndex i = 0; i < size; ++i) {
+        CFDictionaryRef trustSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, i);
+        SecPolicyRef policy = (SecPolicyRef)CFDictionaryGetValue(trustSetting, kSecTrustSettingsPolicy);
+
+        if (isSslPolicy(policy) &&
+            CFDictionaryGetValueIfPresent(trustSetting, kSecTrustSettingsResult,
+                                          (const void **)&result)) {
+            if (!CFNumberGetValue(result, kCFNumberIntType, &result_val))
+                continue;
+            switch (result_val) {
+            case kSecTrustSettingsResultTrustRoot:
+            case kSecTrustSettingsResultTrustAsRoot:
+            case kSecTrustSettingsResultUnspecified:
+                distrusted = false;
+                break;
+            case kSecTrustSettingsResultInvalid:
+            case kSecTrustSettingsResultDeny:
+            default:
+                distrusted = true;
+                break;
+            }
+
+            break;
+        }
+    }
+
+    CFRelease(trustSettings);
+
+    return distrusted;
+}
+
+bool isCertExpired(const unsigned char **bytes, size_t len) {
+    using X509_ptr = std::unique_ptr<X509, decltype(&X509_free)>;
+    X509_ptr cert(d2i_X509(NULL, bytes, len), X509_free);
+    return X509_cmp_current_time (X509_get_notAfter(cert.get())) < 0;
+}
+
+static void
+appendCaCertificateFromSecurityStore(std::vector<QByteArray> *retval,
+                                     SecTrustSettingsDomain domain) {
+    CFArrayRef certs;
+    OSStatus status = 1;
+    status = SecTrustSettingsCopyCertificates(domain, &certs);
+    if (status != errSecSuccess)
+        return;
+
+    CFIndex size = CFArrayGetCount(certs);
+    for (CFIndex i = 0; i < size; ++i) {
+        SecCertificateRef cert =
+            (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
+
+        if (isCertificateDistrustedByUser(cert, kSecTrustSettingsDomainSystem) ||
+            isCertificateDistrustedByUser(cert, kSecTrustSettingsDomainAdmin) ||
+            isCertificateDistrustedByUser(cert, kSecTrustSettingsDomainUser)) {
+            CFStringRef name;
+            status = SecCertificateCopyCommonName(cert, &name);
+            if (status == errSecSuccess && name != nil) {
+                qWarning("declining a distrusted CA certificate from the system"
+                         "store with common name %s",
+                         [(__bridge NSString*)name UTF8String]);
+                CFRelease(name);
+            }
+            else
+                qWarning("declining a distrusted CA certificate from the system store");
+            continue;
+        }
+
+        // copy if trusted
+        CFDataRef data;
+        data = SecCertificateCopyData(cert);
+
+        if (data == NULL) {
+            qWarning("error retrieving a CA certificate from the system store");
+        } else {
+            QByteArray raw_data((const char *)CFDataGetBytePtr(data), CFDataGetLength(data));
+            const unsigned char *pdata = (const unsigned char *)CFDataGetBytePtr(data);
+            // If one of the certs is expired, curl would abort
+            // loading all the certs
+            if (!isCertExpired(&pdata, raw_data.size())) {
+                retval->push_back(raw_data);
+            }
+            CFRelease(data);
+        }
+    }
+    CFRelease(certs);
+}
+
+std::vector<QByteArray> getSystemCaCertificates() {
+    std::vector<QByteArray> retval;
+    appendCaCertificateFromSecurityStore(&retval, kSecTrustSettingsDomainSystem);
+    appendCaCertificateFromSecurityStore(&retval, kSecTrustSettingsDomainAdmin);
+    appendCaCertificateFromSecurityStore(&retval, kSecTrustSettingsDomainUser);
+    return retval;
+}
+
+} // namespace mac
+} // namespace utils
diff --git a/src/utils/utils-win.cpp b/src/utils/utils-win.cpp
new file mode 100644 (file)
index 0000000..1bd63b5
--- /dev/null
@@ -0,0 +1,336 @@
+#include <windows.h>
+#include <shellapi.h>
+#include <wincrypt.h>
+#include <glib.h>
+
+#include <QLibrary>
+#include <QPair>
+#include <QString>
+
+#include "utils/utils-win.h"
+
+namespace utils {
+namespace win {
+
+namespace {
+OSVERSIONINFOEX osver; // static variable, all zero
+bool osver_failure = false;
+
+// From http://stackoverflow.com/a/36909293/1467959 and http://yamatyuu.net/computer/program/vc2013/rtlgetversion/index.html
+typedef void(WINAPI *RtlGetVersion_FUNC)(OSVERSIONINFOEXW *);
+BOOL CustomGetVersion(OSVERSIONINFOEX *os)
+{
+    HMODULE hMod;
+    RtlGetVersion_FUNC func;
+#ifdef UNICODE
+    OSVERSIONINFOEXW *osw = os;
+#else
+    OSVERSIONINFOEXW o;
+    OSVERSIONINFOEXW *osw = &o;
+#endif
+
+    hMod = LoadLibrary(TEXT("ntdll.dll"));
+    if (hMod) {
+        func = (RtlGetVersion_FUNC)GetProcAddress(hMod, "RtlGetVersion");
+        if (func == 0) {
+            FreeLibrary(hMod);
+            return FALSE;
+        }
+        ZeroMemory(osw, sizeof(*osw));
+        osw->dwOSVersionInfoSize = sizeof(*osw);
+        func(osw);
+#ifndef UNICODE
+        os->dwBuildNumber = osw->dwBuildNumber;
+        os->dwMajorVersion = osw->dwMajorVersion;
+        os->dwMinorVersion = osw->dwMinorVersion;
+        os->dwPlatformId = osw->dwPlatformId;
+        os->dwOSVersionInfoSize = sizeof(*os);
+        DWORD sz = sizeof(os->szCSDVersion);
+        WCHAR *src = osw->szCSDVersion;
+        unsigned char *dtc = (unsigned char *)os->szCSDVersion;
+        while (*src)
+            *dtc++ = (unsigned char)*src++;
+        *dtc = '\0';
+#endif
+
+    } else
+        return FALSE;
+    FreeLibrary(hMod);
+    return TRUE;
+}
+
+
+inline bool isInitializedSystemVersion() { return osver.dwOSVersionInfoSize != 0; }
+inline void initializeSystemVersion() {
+    if (isInitializedSystemVersion()) {
+        return;
+    }
+    osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+    // according to the document,
+    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451%28v=vs.85%29.aspx
+    // this API will be unavailable once windows 10 is out
+    if (!CustomGetVersion(&osver)) {
+        qWarning("failed to get OS vesion.");
+        osver_failure = true;
+    }
+}
+
+inline bool _isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
+{
+    initializeSystemVersion();
+    if (osver_failure) {
+        return false;
+    }
+#define OSVER_TO_NUM(major, minor, patch) ((major << 20) + (minor << 10) + (patch))
+#define OSVER_SYS(ver) OSVER_TO_NUM(ver.dwMajorVersion, ver.dwMinorVersion, ver.wServicePackMajor)
+    if (OSVER_SYS(osver) < OSVER_TO_NUM(major, minor, patch)) {
+        return false;
+    }
+#undef OSVER_SYS
+#undef OSVER_TO_NUM
+    return true;
+}
+
+// compile statically
+template<unsigned major, unsigned minor, unsigned patch>
+inline bool isAtLeastSystemVersion()
+{
+    return _isAtLeastSystemVersion(major, minor, patch);
+}
+} // anonymous namesapce
+
+void getSystemVersion(unsigned *major, unsigned *minor, unsigned *patch)
+{
+    initializeSystemVersion();
+    // default to XP
+    if (osver_failure) {
+        *major = 5;
+        *minor = 1;
+        *patch = 0;
+    }
+    *major = osver.dwMajorVersion;
+    *minor = osver.dwMinorVersion;
+    *patch = osver.wServicePackMajor;
+}
+
+bool isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
+{
+    return _isAtLeastSystemVersion(major, minor, patch);
+}
+
+bool isWindowsVistaOrHigher()
+{
+    return isAtLeastSystemVersion<6, 0, 0>();
+}
+
+bool isWindows7OrHigher()
+{
+    return isAtLeastSystemVersion<6, 1, 0>();
+}
+
+bool isWindows8OrHigher()
+{
+    return isAtLeastSystemVersion<6, 2, 0>();
+}
+
+bool isWindows8Point1OrHigher()
+{
+    return isAtLeastSystemVersion<6, 3, 0>();
+}
+
+bool isWindows10OrHigher()
+{
+    return isAtLeastSystemVersion<10, 0, 0>();
+}
+
+typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *);
+typedef BOOL (WINAPI *SetProcessDPIAware)();
+GetDpiForMonitor getDpiForMonitor;
+SetProcessDPIAware setProcessDPIAware;
+typedef QPair<qreal, qreal> QDpi;
+
+static inline QDpi monitorDPI(HMONITOR hMonitor)
+{
+    UINT dpiX;
+    UINT dpiY;
+    if (SUCCEEDED(getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY)))
+        return QDpi(dpiX, dpiY);
+    return QDpi(0, 0);
+}
+
+static inline QDpi deviceDPI(HDC hdc)
+{
+    return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
+}
+
+static bool monitorData(HMONITOR hMonitor, QDpi *dpi_out)
+{
+    MONITORINFOEX info;
+    memset(&info, 0, sizeof(MONITORINFOEX));
+    info.cbSize = sizeof(MONITORINFOEX);
+    if (GetMonitorInfo(hMonitor, &info) == FALSE)
+        return false;
+
+    if (QString::fromLocal8Bit(info.szDevice) == QLatin1String("WinDisc")) {
+        return false;
+    } else {
+        QDpi dpi = monitorDPI(hMonitor);
+        if (dpi.first) {
+            *dpi_out = dpi;
+            return true;
+        } else {
+            HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL);
+            if (hdc) {
+                *dpi_out = deviceDPI(hdc);
+                DeleteDC(hdc);
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+bool monitorEnumCallback(HMONITOR hMonitor, HDC hdc, LPRECT rect, LPARAM p)
+{
+    QDpi *data = (QDpi *)p;
+    if (monitorData(hMonitor, data)) {
+        // printf ("dpi = %d %d\n", (int)data->first, (int)data->second);
+        return false;
+    }
+    return true;
+}
+
+static bool readDPI(QDpi *dpi)
+{
+    EnumDisplayMonitors(0, 0, (MONITORENUMPROC)monitorEnumCallback, (LPARAM)dpi);
+    return dpi->first != 0;
+}
+
+
+// QT's HDPI doesn't support non-integer scale factors, but QT_SCALE_FACTOR
+// environment variable could work with them. So here we calculate the scaling
+// factor (by reading the screen DPI), and update the value QT_SCALE_FACTOR with
+// it.
+//
+// NOTE: The code below only supports single monitor. For multiple monitors we
+// need to detect the dpi of each monitor and set QT_AUTO_SCREEN_SCALE_FACTOR
+// accordingly. We may do that in the future.
+bool fixQtHDPINonIntegerScaling()
+{
+    // Only do this on win8/win10
+    if (!isWindows8OrHigher()) {
+        return false;
+    }
+    // Don't overwrite the user sepcified scaling factors
+    if (!qgetenv("QT_SCALE_FACTOR").isEmpty() || !qgetenv("QT_SCREEN_SCALE_FACTORS").isEmpty()) {
+        return true;
+    }
+    // Don't overwrite the user sepcified multi-screen scaling factors
+    if (!qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR").isEmpty()) {
+        return true;
+    }
+
+    // GetDpiForMonitor and SetProcessDPIAware are only available on win8/win10.
+    //
+    // See:
+    //   - GetDpiForMonitor https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx
+    //   - SetProcessDPIAware https://msdn.microsoft.com/en-us/library/windows/desktop/ms633543(v=vs.85).aspx
+    QLibrary shcore_dll(QString("SHCore"));
+    getDpiForMonitor = (GetDpiForMonitor)shcore_dll.resolve("GetDpiForMonitor");
+    if (getDpiForMonitor == nullptr) {
+        return false;
+    }
+
+    QLibrary user32_dll(QString("user32"));
+    setProcessDPIAware = (SetProcessDPIAware)user32_dll.resolve("SetProcessDPIAware");
+    if (setProcessDPIAware == nullptr) {
+        return false;
+    }
+
+    // Turn off system scaling, otherwise we'll always see a 96 DPI virtual screen.
+    if (!setProcessDPIAware()) {
+        return false;
+    }
+
+    QDpi dpi;
+    if (!readDPI(&dpi)) {
+        return false;
+    }
+
+    if (dpi.first <= 96) {
+        return false;
+    }
+
+    // See the "DPI and the Desktop Scaling Factor" https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx#dpi_and_the_desktop_scaling_factor
+    // Specifically, MSDN says:
+    //     96 DPI = 100% scaling
+    //     120 DPI = 125% scaling
+    //     144 DPI = 150% scaling
+    //     192 DPI = 200% scaling
+    double scaling_factor = ((double)(dpi.first)) / 96.0;
+    QString factor = QString::number(scaling_factor);
+
+    // Use QT_SCREEN_SCALE_FACTORS instead of QT_SCALE_FACTOR. The latter would
+    // scale the font, which has already been scaled by the system.
+    //
+    // See also http://lists.qt-project.org/pipermail/interest/2015-October/019242.html
+    g_setenv("QT_SCREEN_SCALE_FACTORS", factor.toUtf8().data(), 1);
+    // printf("set QT_SCALE_FACTOR to %s\n", factor.toUtf8().data());
+    return true;
+}
+
+char *b64encode(const char *input)
+{
+    char buf[32767] = {0};
+    DWORD retlen = 32767;
+    CryptBinaryToString((BYTE*) input, strlen(input), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, buf, &retlen);
+    return strdup(buf);
+}
+
+std::string getLocalPipeName(const char *pipe_name)
+{
+    DWORD buf_char_count = 32767;
+    char user_name_buf[buf_char_count];
+
+    if (GetUserName(user_name_buf, &buf_char_count) == 0) {
+        qWarning ("Failed to get user name, GLE=%lu\n",
+                  GetLastError());
+        return pipe_name;
+    }
+    else {
+        std::string ret(pipe_name);
+        char *encoded = b64encode(user_name_buf);
+        ret += encoded;
+        free(encoded);
+        return ret;
+    }
+}
+
+// Qt's QProcess function cannot invoke programs that require administrator privileges,
+// so we need windows api funtion to invoke the program that require adminstrator privileges.
+DWORD runShellAsAdministrator(LPCSTR cmd, LPCSTR arg, int n_show)
+{
+    SHELLEXECUTEINFO shell_exec_info = {0};
+    shell_exec_info.cbSize = sizeof(SHELLEXECUTEINFO);
+    shell_exec_info.fMask = SEE_MASK_NOCLOSEPROCESS;
+    shell_exec_info.hwnd = NULL;
+    shell_exec_info.lpVerb = "runas";
+    shell_exec_info.lpFile = cmd;
+    shell_exec_info.lpParameters = arg;
+    shell_exec_info.lpDirectory = NULL;
+    shell_exec_info.nShow = n_show;
+    shell_exec_info.hInstApp = NULL;
+
+    BOOL ret = ShellExecuteEx(&shell_exec_info);
+    WaitForSingleObject(shell_exec_info.hProcess, INFINITE);
+
+    DWORD exit_code=0;
+    GetExitCodeProcess(shell_exec_info.hProcess, &exit_code);
+    CloseHandle(shell_exec_info.hProcess);
+    return exit_code;
+}
+
+
+} // namespace win
+
+} // namespace utils
diff --git a/src/utils/utils-win.h b/src/utils/utils-win.h
new file mode 100644 (file)
index 0000000..6f4de25
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef SEAFILE_CLIENT_UTILS_WIN_H_
+#define SEAFILE_CLIENT_UTILS_WIN_H_
+#include <QtGlobal>
+
+#ifdef Q_OS_WIN32
+#include <windows.h>
+#endif
+
+#ifdef Q_OS_WIN32
+namespace utils {
+namespace win {
+// a list for windows versions https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833%28v=vs.85%29.aspx
+// Windows Relaese        major    minor   patch(SP)
+// windows 10:            10,      0,      ?
+// windows 8.1:           6,       3,      ?
+// windows 2012 R2:       6,       3,      ?
+// windows 8:             6,       2,      ?
+// windows 2012:          6,       2,      ?
+// windows 7:             6,       1,      ?
+// windows 2008 R2:       6,       1,      ?
+// windows Vista:         6,       0,      ?
+// windows 2008:          6,       0,      ?
+// windows 2003 R2:       5,       2,      ?
+// windows 2003:          5,       2,      ?
+// windows XP x64:        5,       2,      ?
+// windows XP:            5,       1,      ?
+// windows 2000:          5,       0,      ?
+void getSystemVersion(unsigned *major, unsigned *minor, unsigned *patch);
+bool isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch);
+
+bool isWindowsVistaOrGreater();
+bool isWindows7OrGreater();
+bool isWindows8OrGreater();
+bool isWindows8Point1OrGreater();
+bool isWindows10OrHigher();
+bool fixQtHDPINonIntegerScaling();
+std::string getLocalPipeName(const char *pipeName);
+DWORD runShellAsAdministrator(LPCSTR cmd, LPCSTR arg, int n_show);
+} // namespace win
+} // namespace utils
+#endif
+
+
+#endif // SEAFILE_CLIENT_UTILS_WIN_H_
diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp
new file mode 100644 (file)
index 0000000..5e6a6d6
--- /dev/null
@@ -0,0 +1,864 @@
+#include <cassert>
+#include <errno.h>
+#include <dirent.h>
+#include <cstdio>
+#include <cstdlib>
+#include <unistd.h>
+#include <sqlite3.h>
+#include <glib.h>
+#include <cstring>
+#include <QObject>
+#include <QString>
+#include <QSettings>
+#include <QProcess>
+#include <QDesktopServices>
+#include <QHostInfo>
+#include <jansson.h>
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QUrlQuery>
+#endif
+
+#include "utils/utils-mac.h"
+#include "utils/utils-win.h"
+
+#if defined(Q_OS_MAC)
+    #include <sys/sysctl.h>
+#elif defined(Q_OS_WIN32)
+    #include <windows.h>
+    #include <psapi.h>
+#endif
+
+#include <QMap>
+#include <QVariant>
+#include <QDebug>
+#include <QDateTime>
+#include <QCryptographicHash>
+#include <QSslCipher>
+#include <QSslCertificate>
+
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+
+#include "utils/utils.h"
+
+namespace {
+
+const char *kSeafileClientBrand = "Seafile";
+#if defined(Q_OS_WIN32)
+const char *kCcnetConfDir = "ccnet";
+#else
+const char *kCcnetConfDir = ".ccnet";
+#endif
+
+#ifdef Q_OS_LINUX
+/// \brief call xdg-mime to find out the mime filetype X11 recognizes it as
+/// xdg-mime's usage:
+/// xdg-mime query filetype <filename>
+/// stdout: mime-type
+bool getMimeTypeFromXdgUtils(const QString &filepath, QString *mime)
+{
+    QProcess subprocess;
+    QStringList args("query");
+    args.push_back("filetype");
+    args.push_back(filepath);
+    subprocess.start(QLatin1String("xdg-mime"), args);
+    subprocess.waitForFinished(-1);
+    if (subprocess.exitCode())
+        return false;
+    *mime = subprocess.readAllStandardOutput();
+    *mime = mime->trimmed();
+    if (mime->isEmpty())
+        return false;
+    return true;
+}
+
+/// \brief call xdg-mime to find out the application X11 opens with by mime filetype
+/// xdg-mime's usage:
+/// xdg-mime query default <filename>
+/// stdout: application
+bool getOpenApplicationFromXdgUtils(const QString &mime, QString *application)
+{
+    QProcess subprocess;
+    QStringList args("query");
+    args.push_back("default");
+    args.push_back(mime);
+    subprocess.start(QLatin1String("xdg-mime"), args);
+    subprocess.waitForFinished(-1);
+    if (subprocess.exitCode())
+        return false;
+    *application = subprocess.readAllStandardOutput();
+    *application = application->trimmed();
+    if (application->isEmpty())
+        return false;
+    return true;
+}
+#endif
+
+} // namespace
+
+
+QString defaultCcnetDir() {
+    const char *env = g_getenv("CCNET_CONF_DIR");
+    if (env) {
+        return QString::fromUtf8(env);
+    } else {
+        return QDir::home().filePath(kCcnetConfDir);
+    }
+}
+
+QString defaultDownloadDir() {
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    static QStringList list = QStandardPaths::standardLocations(QStandardPaths::DownloadLocation);
+    if (!list.empty())
+        return list.front();
+#endif
+    // qt4 don't have QStandardPaths, use glib's as fallback
+    return QString::fromUtf8(g_get_user_special_dir(G_USER_DIRECTORY_DOWNLOAD));
+}
+
+bool openInNativeExtension(const QString &path) {
+#if defined(Q_OS_WIN32)
+    //call ShellExecute internally
+    return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
+#elif defined(Q_OS_MAC)
+    // mac's open program, it will fork to open the file in a subprocess
+    // so we will wait for it to check whether it succeeds or not
+    QProcess subprocess;
+    subprocess.start(QLatin1String("open"), QStringList(path));
+    subprocess.waitForFinished(-1);
+    return subprocess.exitCode() == 0;
+#elif defined(Q_OS_LINUX)
+    // unlike mac's open program, xdg-open won't fork a new subprocess to open
+    // the file will block until the application returns, so we won't wait for it
+    // and we need another approach to check if it works
+
+    // find out if the file can be opened by xdg-open, xdg-mime
+    // usually they are installed in xdg-utils installed by default
+    QString mime_type;
+    if (!getMimeTypeFromXdgUtils(path, &mime_type))
+        return false;
+    // don't open this type of files from xdg-mime
+    if (mime_type == "application/octet-stream")
+        return false;
+    // in fact we need to filter out files like application/x-executable
+    // but it is not necessary since getMimeTypeFromXdg will return false for
+    // it!
+    QString application;
+    if (!getOpenApplicationFromXdgUtils(mime_type, &application))
+        return false;
+
+    return QProcess::startDetached(QLatin1String("xdg-open"),
+                                   QStringList(path));
+#else
+    return false;
+#endif
+}
+
+bool showInGraphicalShell(const QString& path) {
+#if defined(Q_OS_WIN32)
+    QStringList params;
+    if (!QFileInfo(path).isDir())
+        params << QLatin1String("/select,");
+    params << QDir::toNativeSeparators(path);
+    return QProcess::startDetached(QLatin1String("explorer.exe"), params);
+#elif defined(Q_OS_MAC)
+    QStringList scriptArgs;
+    scriptArgs << QLatin1String("-e")
+               << QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"")
+                                     .arg(path);
+    QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs);
+    scriptArgs.clear();
+    scriptArgs << QLatin1String("-e")
+               << QLatin1String("tell application \"Finder\" to activate");
+    QProcess::execute("/usr/bin/osascript", scriptArgs);
+    return true;
+#else
+    return QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(path).absolutePath()));
+#endif
+}
+
+typedef bool (*SqliteRowFunc) (sqlite3_stmt *stmt, void *data);
+
+sqlite3_stmt *
+sqlite_query_prepare (sqlite3 *db, const char *sql)
+{
+    sqlite3_stmt *stmt;
+    int result;
+
+    result = sqlite3_prepare_v2 (db, sql, -1, &stmt, NULL);
+
+    if (result != SQLITE_OK) {
+        const gchar *str = sqlite3_errmsg (db);
+
+        g_warning ("Couldn't prepare query, error:%d->'%s'\n\t%s\n",
+                   result, str ? str : "no error given", sql);
+
+        return NULL;
+    }
+
+    return stmt;
+}
+
+int sqlite_query_exec (sqlite3 *db, const char *sql)
+{
+    char *errmsg = NULL;
+    int result;
+
+    result = sqlite3_exec (db, sql, NULL, NULL, &errmsg);
+
+    if (result != SQLITE_OK) {
+        if (errmsg != NULL) {
+            g_warning ("SQL error: %d - %s\n:\t%s\n", result, errmsg, sql);
+            sqlite3_free (errmsg);
+        }
+        return -1;
+    }
+
+    return 0;
+}
+
+int sqlite_foreach_selected_row (sqlite3 *db, const char *sql,
+                                 SqliteRowFunc callback, void *data)
+{
+    sqlite3_stmt *stmt;
+    int result;
+    int n_rows = 0;
+
+    stmt = sqlite_query_prepare (db, sql);
+    if (!stmt) {
+        return -1;
+    }
+
+    while (1) {
+        result = sqlite3_step (stmt);
+        if (result != SQLITE_ROW)
+            break;
+        n_rows++;
+        if (!callback (stmt, data))
+            break;
+    }
+
+    if (result == SQLITE_ERROR) {
+        const gchar *s = sqlite3_errmsg (db);
+
+        g_warning ("Couldn't execute query, error: %d->'%s'\n",
+                   result, s ? s : "no error given");
+        sqlite3_finalize (stmt);
+        return -1;
+    }
+
+    sqlite3_finalize (stmt);
+    return n_rows;
+}
+
+int checkdir_with_mkdir (const char *dir)
+{
+#if defined(Q_OS_WIN32)
+    int ret;
+    char *path = g_strdup(dir);
+    char *p = (char *)path + strlen(path) - 1;
+    while (*p == '\\' || *p == '/') *p-- = '\0';
+    ret = g_mkdir_with_parents(path, 0755);
+    g_free (path);
+    return ret;
+#else
+    return g_mkdir_with_parents(dir, 0755);
+#endif
+}
+
+
+#if defined(Q_OS_WIN32)
+static LONG
+get_win_run_key (HKEY *pKey)
+{
+    const char *key_run = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
+    LONG result = RegOpenKeyEx(
+        /* We don't use HKEY_LOCAL_MACHINE here because that requires
+         * seaf-daemon to run with admin privilege. */
+                               HKEY_CURRENT_USER,
+                               key_run,
+                               0L,KEY_WRITE | KEY_READ,
+                               pKey);
+    if (result != ERROR_SUCCESS) {
+        qWarning("Failed to open Registry key %s\n", key_run);
+    }
+
+    return result;
+}
+
+static int
+add_to_auto_start (const wchar_t *appname_w, const wchar_t *path_w)
+{
+    HKEY hKey;
+    LONG result = get_win_run_key(&hKey);
+    if (result != ERROR_SUCCESS) {
+        return -1;
+    }
+
+    DWORD n = sizeof(wchar_t) * (wcslen(path_w) + 1);
+
+    result = RegSetValueExW (hKey, appname_w,
+                             0, REG_SZ, (const BYTE *)path_w, n);
+
+    RegCloseKey(hKey);
+    if (result != ERROR_SUCCESS) {
+        qWarning("Failed to create auto start value\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+delete_from_auto_start(const wchar_t *appname)
+{
+    HKEY hKey;
+    LONG result = get_win_run_key(&hKey);
+    if (result != ERROR_SUCCESS) {
+        return -1;
+    }
+
+    result = RegDeleteValueW (hKey, appname);
+    RegCloseKey(hKey);
+    if (result != ERROR_SUCCESS) {
+        qWarning("Failed to remove auto start value");
+        return -1;
+    }
+
+    return 0;
+}
+
+int
+get_seafile_auto_start()
+{
+    HKEY hKey;
+    LONG result = get_win_run_key(&hKey);
+    if (result != ERROR_SUCCESS) {
+        return -1;
+    }
+
+    char buf[MAX_PATH] = {0};
+    DWORD len = sizeof(buf);
+    result = RegQueryValueExW (hKey,             /* Key */
+                               getBrand().toStdWString().c_str(),        /* value */
+                               NULL,             /* reserved */
+                               NULL,             /* output type */
+                               (LPBYTE)buf,      /* output data */
+                               &len);            /* output length */
+
+    RegCloseKey(hKey);
+    if (result != ERROR_SUCCESS) {
+        /* seafile applet auto start no set  */
+        return 0;
+    }
+
+    return 1;
+}
+
+int
+set_seafile_auto_start(bool on)
+{
+    int result = 0;
+    if (on) {
+        /* turn on auto start  */
+        wchar_t applet_path[MAX_PATH];
+        if (GetModuleFileNameW (NULL, applet_path, MAX_PATH) == 0) {
+            return -1;
+        }
+
+        result = add_to_auto_start (getBrand().toStdWString().c_str(), applet_path);
+
+    } else {
+        /* turn off auto start */
+        result = delete_from_auto_start(getBrand().toStdWString().c_str());
+    }
+    return result;
+}
+
+#elif defined(Q_OS_MAC)
+int
+get_seafile_auto_start()
+{
+    return utils::mac::get_auto_start();
+}
+
+int
+set_seafile_auto_start(bool on)
+{
+    bool was_on = utils::mac::get_auto_start();
+    if (on != was_on)
+        utils::mac::set_auto_start(on);
+    return on;
+}
+#else
+int
+get_seafile_auto_start()
+{
+    return 0;
+}
+
+int
+set_seafile_auto_start(bool /* on */)
+{
+    return 0;
+}
+
+#endif
+
+int
+set_seafile_dock_icon_style(bool hidden)
+{
+#if defined(Q_OS_MAC)
+    utils::mac::setDockIconStyle(hidden);
+#endif
+    return 0;
+}
+
+bool parse_key_value_pairs (char *string, KeyValueFunc func, void *data)
+{
+    char *line = string, *next, *space;
+    char *key, *value;
+
+    while (*line) {
+        /* handle empty line */
+        if (*line == '\n') {
+            ++line;
+            continue;
+        }
+
+        for (next = line; *next != '\n' && *next; ++next) ;
+        *next = '\0';
+
+        for (space = line; space < next && *space != ' '; ++space) ;
+        if (*space != ' ') {
+            return false;
+        }
+        *space = '\0';
+        key = line;
+        value = space + 1;
+
+        if (func(data, key, value) == FALSE)
+            return false;
+
+        line = next + 1;
+    }
+    return true;
+}
+
+QString getBrand()
+{
+    return QString::fromUtf8(kSeafileClientBrand);
+}
+
+static
+QList<QVariant> listFromJSON(json_t *array)
+{
+    QList<QVariant> ret;
+    size_t array_size = json_array_size(array);
+    json_t *value;
+
+    for(size_t index = 0; index < array_size &&
+        (value = json_array_get(array, index)); ++index) {
+        /* block of code that uses index and value */
+        QVariant v;
+        if (json_is_object(value)) {
+            v = mapFromJSON(value, NULL);
+        } else if (json_is_array(value)) {
+            v = listFromJSON(value);
+        } else if (json_is_string(value)) {
+            v = QString::fromUtf8(json_string_value(value));
+        } else if (json_is_integer(value)) {
+            v = json_integer_value(value);
+        } else if (json_is_real(value)) {
+            v = json_real_value(value);
+        } else if (json_is_boolean(value)) {
+            v = json_is_true(value);
+        }
+        if (v.isValid()) {
+          ret.push_back(v);
+        }
+    }
+    return ret;
+}
+
+QMap<QString, QVariant> mapFromJSON(json_t *json, json_error_t *error)
+{
+    QMap<QString, QVariant> dict;
+    void *member;
+    const char *key;
+    json_t *value;
+
+    for (member = json_object_iter(json); member; member = json_object_iter_next(json, member)) {
+        key = json_object_iter_key(member);
+        value = json_object_iter_value(member);
+
+        QString k = QString::fromUtf8(key);
+        QVariant v;
+
+        // json_is_object(const json_t *json)
+        // json_is_array(const json_t *json)
+        // json_is_string(const json_t *json)
+        // json_is_integer(const json_t *json)
+        // json_is_real(const json_t *json)
+        // json_is_true(const json_t *json)
+        // json_is_false(const json_t *json)
+        // json_is_null(const json_t *json)
+        if (json_is_object(value)) {
+            v = mapFromJSON(value, NULL);
+        } else if (json_is_array(value)) {
+            v = listFromJSON(value);
+        } else if (json_is_string(value)) {
+            v = QString::fromUtf8(json_string_value(value));
+        } else if (json_is_integer(value)) {
+            v = json_integer_value(value);
+        } else if (json_is_real(value)) {
+            v = json_real_value(value);
+        } else if (json_is_boolean(value)) {
+            v = json_is_true(value);
+        }
+
+        if (v.isValid()) {
+            dict[k] = v;
+        }
+    }
+    return dict;
+}
+
+QString mapToJson(QMap<QString, QVariant> map)
+{
+    json_t *object = NULL;
+    char *info = NULL;
+    object = json_object();
+
+    Q_FOREACH (const QString &k, map.keys()) {
+        QVariant v = map.value(k);
+        switch (v.type()) {
+        case QVariant::String:
+            json_object_set_new(object, toCStr(k), json_string(toCStr(v.toString())));
+            break;
+        case QVariant::Int:
+            json_object_set_new(object, toCStr(k), json_integer(v.toInt()));
+            break;
+            // TODO: support other types
+        default:
+            continue;
+        }
+    }
+
+    info = json_dumps(object, 0);
+    QString ret = QString::fromUtf8(info);
+    json_decref (object);
+    free (info);
+    return ret;
+}
+
+QString translateCommitTime(qint64 timestamp, bool hours_and_minutes) {
+    timestamp *= 1000;          // use milli seconds
+    qint64 now = QDateTime::currentMSecsSinceEpoch();
+    if (now <= timestamp) {
+        return QObject::tr("Just now");
+    }
+
+    qint64 delta = (now - timestamp) / 1000;
+
+    qint64 secondsPerDay = 24 * 60 * 60;
+
+    qint64 days = delta / secondsPerDay;
+    qint64 seconds = delta % secondsPerDay;
+
+    QDateTime dt = QDateTime::fromMSecsSinceEpoch(timestamp);
+
+    if (hours_and_minutes) {
+        return dt.toString("yyyy-MM-dd HH:mm");
+    }
+
+    if (days >= 14) {
+        return dt.toString("yyyy-MM-dd");
+
+    } else if (days > 0) {
+        return days == 1 ? QObject::tr("1 day ago") : QObject::tr("%1 days ago").arg(days);
+
+    } else if (seconds >= 60 * 60) {
+        qint64 hours = seconds / 3600;
+        return hours == 1 ? QObject::tr("1 hour ago") : QObject::tr("%1 hours ago").arg(hours);
+
+    } else if (seconds >= 60) {
+        qint64 minutes = seconds / 60;
+        return minutes == 1 ? QObject::tr("1 minute ago") : QObject::tr("%1 minutes ago").arg(minutes);
+
+    } else if (seconds > 0) {
+        // return seconds == 1 ? QObject::tr("1 second ago") : QObject::tr("%1 seconds ago").arg(seconds);
+        return QObject::tr("Just now");
+
+    } else {
+        return QObject::tr("Just now");
+    }
+}
+
+QString readableFileSize(qint64 size)
+{
+    QString str;
+    double value = (double)size;
+    int precision = 1;
+
+    if (value < 1000) {
+        str = "B";
+        precision = 0;
+    } else if (value >= 1000 && value < 1000*1000) {
+        value = value / 1000;
+        str = "KB";
+        precision = 0;
+    } else if (value >= 1000*1000 && value < 1000*1000*1000) {
+        value = value / 1000 / 1000;
+        str = "MB";
+    } else if (value >= 1000*1000*1000) {
+        value = value / 1000 / 1000 / 1000;
+        str = "GB";
+    }
+
+    return QString::number(value, 'f', precision) + str;
+}
+
+QString readableFileSizeV2(qint64 size)
+{
+    return readableFileSize(size);
+}
+
+
+QString md5(const QString& s)
+{
+    return QCryptographicHash::hash(s.toUtf8(), QCryptographicHash::Md5).toHex();
+}
+
+QUrl urlJoin(const QUrl& head, const QString& tail)
+{
+    QString a = head.toString();
+    QString b = tail;
+
+    if (!a.endsWith("/")) {
+        a += "/";
+    }
+    while (b.startsWith("/")) {
+        b = b.mid(1);
+    }
+    return QUrl(a + b);
+}
+
+void removeDirRecursively(const QString &path)
+{
+    QFileInfo file_info(path);
+    if (file_info.isDir()) {
+        QDir dir(path);
+        QStringList file_list = dir.entryList();
+        for (int i = 0; i < file_list.count(); ++i) {
+            removeDirRecursively(file_list.at(i));
+        }
+        removeDirRecursively(path);
+    } else {
+        QFile::remove(path);
+    }
+}
+
+QString dumpHexPresentation(const QByteArray &bytes)
+{
+    if (bytes.size() < 2)
+      return QString(bytes).toUpper();
+    QString output((char)bytes[0]);
+    output += (char)bytes[1];
+    for (int i = 2 ; i != bytes.size() ; i++) {
+      if (i % 2 == 0)
+        output += ':';
+      output += (char)bytes[i];
+    }
+    return output.toUpper();
+}
+
+QString dumpCipher(const QSslCipher &cipher)
+{
+    QString s = "\n";
+    s += "Authentication:  " + cipher.authenticationMethod() + "\n";
+    s += "Encryption:      " + cipher.encryptionMethod() + "\n";
+    s += "Key Exchange:    " + cipher.keyExchangeMethod() + "\n";
+    s += "Cipher Name:     " + cipher.name() + "\n";
+    s += "Protocol:        " +  cipher.protocolString() + "\n";
+    s += "Supported Bits:  " + QString(cipher.supportedBits()) + "\n";
+    s += "Used Bits:       " + QString(cipher.usedBits()) + "\n";
+    return s;
+}
+
+QString dumpCertificate(const QSslCertificate &cert)
+{
+    if (cert.isNull())
+      return "\n-\n";
+
+    QString s = "\n";
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    s += cert.toText();
+#else
+    QString s_none = QObject::tr("<Not Part of Certificate>");
+    #define CERTIFICATE_STR(x) ( ((x) == "" ) ? s_none : (x) )
+
+    s += "Certificate:\n";
+    s += "\nIssued To:\n";
+    s += "CommonName(CN):             " + CERTIFICATE_STR(cert.subjectInfo(QSslCertificate::CommonName)) + "\n";
+    s += "Organization(O):            " + CERTIFICATE_STR(cert.subjectInfo(QSslCertificate::Organization)) + "\n";
+    s += "OrganizationalUnitName(OU): " + CERTIFICATE_STR(cert.subjectInfo(QSslCertificate::OrganizationalUnitName)) + "\n";
+    s += "Serial Number:              " + dumpHexPresentation(cert.serialNumber()) + "\n";
+
+    s += "\nIssued By:\n";
+    s += "CommonName(CN):             " + CERTIFICATE_STR(cert.issuerInfo(QSslCertificate::CommonName)) + "\n";
+    s += "Organization(O):            " + CERTIFICATE_STR(cert.issuerInfo(QSslCertificate::Organization)) + "\n";
+    s += "OrganizationalUnitName(OU): " + CERTIFICATE_STR(cert.issuerInfo(QSslCertificate::OrganizationalUnitName)) + "\n";
+
+    s += "\nPeriod Of Validity\n";
+    s += "Begins On:    " + cert.effectiveDate().toString() + "\n";
+    s += "Expires On:   " + cert.expiryDate().toString() + "\n";
+    s += "IsValid:      " + (cert.isValid() ? QString("Yes") : QString("No")) + "\n";
+
+    s += "\nFingerprints\n";
+    s += "SHA1 Fingerprint:\n" + dumpCertificateFingerprint(cert, QCryptographicHash::Sha1) + "\n";
+    s += "MD5 Fingerprint:\n" + dumpCertificateFingerprint(cert, QCryptographicHash::Md5) + "\n";
+#endif
+
+    s += "\n\n";
+    s += cert.toPem();
+
+    return s;
+}
+
+QString dumpCertificateFingerprint(const QSslCertificate &cert, const QCryptographicHash::Algorithm &algorithm)
+{
+    if(cert.isNull())
+      return "";
+    return dumpHexPresentation(cert.digest(algorithm).toHex());
+}
+
+QString dumpSslErrors(const QList<QSslError> &errors)
+{
+    QString s;
+    foreach (const QSslError &error, errors) {
+        s += error.errorString() + "\n";
+    }
+    return s;
+}
+
+void msleep(int mseconds)
+{
+#ifdef Q_OS_WIN32
+    ::Sleep(mseconds);
+#else
+    struct timespec ts;
+    ts.tv_sec = mseconds / 1000;
+    ts.tv_nsec = mseconds % 1000 * 1000 * 1000;
+
+    int r;
+    do {
+        r = ::nanosleep(&ts, &ts);
+    } while (r == -1 && errno == EINTR);
+#endif
+}
+
+QUrl includeQueryParams(const QUrl& url,
+                        const QHash<QString, QString>& params)
+{
+    QUrl u(url);
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    QUrlQuery query;
+    Q_FOREACH (const QString& key, params.keys()) {
+        QString value = params[key];
+        query.addQueryItem(QUrl::toPercentEncoding(key),
+                           QUrl::toPercentEncoding(value));
+    }
+    u.setQuery(query);
+#else
+    Q_FOREACH (const QString& key, params.keys()) {
+        QString value = params[key];
+        u.addEncodedQueryItem(QUrl::toPercentEncoding(key),
+                              QUrl::toPercentEncoding(value));
+    }
+#endif
+    return u;
+}
+
+QByteArray buildFormData(const QHash<QString, QString>& params)
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+    QUrlQuery query;
+    Q_FOREACH (const QString& key, params.keys()) {
+        QString value = params[key];
+        query.addQueryItem(QUrl::toPercentEncoding(key),
+                           QUrl::toPercentEncoding(value));
+
+    }
+    return query.query(QUrl::FullyEncoded).toUtf8();
+#else
+    QUrl u;
+    Q_FOREACH (const QString& key, params.keys()) {
+        QString value = params[key];
+        u.addEncodedQueryItem(QUrl::toPercentEncoding(key),
+                              QUrl::toPercentEncoding(value));
+    }
+    return u.encodedQuery();
+#endif
+}
+
+int digitalCompare(const QString &left, const QString &right)
+{
+    int ret = 0;
+    if (left.compare(right, Qt::CaseInsensitive) == 0)
+        return ret;
+    if (left.size() == 0)
+        return -1;
+    if (right.size() == 0)
+        return 1;
+
+    QString left_sub = left;
+    QString right_sub = right;
+    const uint min_size = left.size() < right.size()
+                          ? left.size() : right.size();
+    uint i;
+    for (i = 0; i != min_size; i++) {
+        if (left[i].isDigit() && right[i].isDigit())
+            break;
+        if (left[i] != right[i])
+            return left.compare(right, Qt::CaseInsensitive);
+    }
+    left_sub = left_sub.right(left_sub.size() - i);
+    right_sub = right_sub.right(right_sub.size() - i);
+
+    const QRegExp left_digit_pattern("(\\d+)*");
+    const QRegExp right_digit_pattern("(\\d+)*");
+    const int left_pos = left_digit_pattern.indexIn(left_sub);
+    const int right_pos = right_digit_pattern.indexIn(right_sub);
+    if (left_pos == 0 && right_pos == 0) {
+        quint64 left_digit = left_digit_pattern.cap(1).toUInt();
+        quint64 right_digit = right_digit_pattern.cap(1).toUInt();
+        if (left_digit == right_digit) {
+            left_sub = left_sub.right(left_sub.size() -
+                                      left_digit_pattern.cap(1).size());
+            right_sub = right_sub.right(right_sub.size() -
+                                        right_digit_pattern.cap(1).size());
+            return digitalCompare(left_sub, right_sub);
+        }
+        return left_digit - right_digit;
+    }
+    return left.compare(right, Qt::CaseInsensitive);
+}
+
+bool shouldUseFramelessWindow()
+{
+    static int _shouldUseFramelessWindow = -1;
+
+    if (_shouldUseFramelessWindow < 0) {
+        _shouldUseFramelessWindow = 1;
+#if defined(Q_OS_MAC)
+        _shouldUseFramelessWindow = 0;
+#elif defined(Q_OS_WIN32)
+        if (utils::win::isWindows10OrHigher()) {
+            _shouldUseFramelessWindow = 0;
+        }
+#endif
+    }
+
+    return _shouldUseFramelessWindow > 0;
+}
diff --git a/src/utils/utils.h b/src/utils/utils.h
new file mode 100644 (file)
index 0000000..b507c10
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef SEAFILE_CLIENT_UTILS_H_
+#define SEAFILE_CLIENT_UTILS_H_
+
+#include <jansson.h>
+#include <QString>
+#include <QDir>
+#include <QMap>
+#include <QHash>
+#include <QUrl>
+#include <QSslError>
+
+class QSslCipher;
+class QSslCertificate;
+
+#define toCStr(_s)   ((_s).isNull() ? NULL : (_s).toUtf8().data())
+
+#if defined(XCODE_APP)
+#define RESOURCE_PATH(_name)  (QDir(QCoreApplication::applicationDirPath()).filePath(QString("../Resources/")+(_name)))
+#else
+#define RESOURCE_PATH(_name)  (_name)
+#endif
+
+struct sqlite3;
+struct sqlite3_stmt;
+
+typedef bool (*SqliteRowFunc) (sqlite3_stmt *stmt, void *data);
+
+sqlite3_stmt *sqlite_query_prepare (sqlite3 *db, const char *sql);
+
+int sqlite_query_exec (sqlite3 *db, const char *sql);
+
+int sqlite_foreach_selected_row (sqlite3 *db, const char *sql,
+                                 SqliteRowFunc callback, void *data);
+
+int checkdir_with_mkdir (const char *dir);
+
+int get_seafile_auto_start();
+
+int set_seafile_auto_start(bool on);
+
+int set_seafile_dock_icon_style(bool hidden);
+
+typedef bool (*KeyValueFunc) (void *data, const char *key,
+                              const char *value);
+
+bool parse_key_value_pairs (char *string, KeyValueFunc func, void *data);
+
+QString getBrand();
+
+QString translateCommitTime(qint64 timestamp, bool hours_and_minutes = false);
+
+QString readableFileSize(qint64 size);
+
+QString readableFileSizeV2(qint64 size);
+
+QMap<QString, QVariant> mapFromJSON(json_t *json, json_error_t *error);
+QString mapToJson(QMap<QString, QVariant> map);
+
+QString defaultCcnetDir();
+
+QString defaultDownloadDir();
+
+// open file use native default file handler, return false if failed
+bool openInNativeExtension(const QString &path);
+
+// open file and select it in native file browser, return false if failed
+bool showInGraphicalShell(const QString& path);
+
+QString md5(const QString& s);
+
+QUrl urlJoin(const QUrl& url, const QString& tail);
+
+void removeDirRecursively(const QString &path);
+
+QString dumpHexPresentation(const QByteArray &bytes);
+
+QString dumpSslErrors(const QList<QSslError>&);
+
+QString dumpCipher(const QSslCipher &cipher);
+
+QString dumpCertificate(const QSslCertificate &cert);
+
+QString dumpCertificateFingerprint(const QSslCertificate &cert,
+                                   const QCryptographicHash::Algorithm &algorithm = QCryptographicHash::Md5);
+
+void msleep(int mseconds);
+
+
+QUrl includeQueryParams(const QUrl& url,
+                        const QHash<QString, QString>& params);
+
+QByteArray buildFormData(const QHash<QString, QString>& params);
+
+int digitalCompare(const QString &left, const QString &right);
+
+bool shouldUseFramelessWindow();
+
+#endif
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_file-utils.cpp b/tests/test_file-utils.cpp
new file mode 100644 (file)
index 0000000..980218d
--- /dev/null
@@ -0,0 +1,47 @@
+#include "test_file-utils.h"
+#include <QtTest/QtTest>
+
+#include "../src/utils/file-utils.h"
+
+void FileUtils::getParentPath() {
+    using ::getParentPath;
+    QCOMPARE(getParentPath("/"), QString("/"));
+    QCOMPARE(getParentPath("//"), QString("/"));
+    QCOMPARE(getParentPath("/usr"), QString("/"));
+    QCOMPARE(getParentPath("/usr/"), QString("/"));
+    QCOMPARE(getParentPath("/usr/bin"), QString("/usr"));
+    QCOMPARE(getParentPath("/usr/bin/"), QString("/usr"));
+    QCOMPARE(getParentPath("/usr.complicate"), QString("/"));
+    QCOMPARE(getParentPath("/usr/bin.pdf"), QString("/usr"));
+    QCOMPARE(getParentPath(QString::fromUtf8("/usr/測試")), QString::fromUtf8("/usr"));
+    QCOMPARE(getParentPath(QString::fromUtf8("/√∆/測試")), QString::fromUtf8("/√∆"));
+}
+
+void FileUtils::getBaseName() {
+    using ::getBaseName;
+    QCOMPARE(getBaseName("/"), QString("/"));
+    QCOMPARE(getBaseName("//"), QString("/"));
+    QCOMPARE(getBaseName("/usr"), QString("usr"));
+    QCOMPARE(getBaseName("/usr/"), QString("usr"));
+    QCOMPARE(getBaseName("/usr/bin"), QString("bin"));
+    QCOMPARE(getBaseName("/usr/bin/"), QString("bin"));
+    QCOMPARE(getBaseName("/usr.complicate"), QString("usr.complicate"));
+    QCOMPARE(getBaseName("/usr/bin.pdf"), QString("bin.pdf"));
+    QCOMPARE(getBaseName(QString::fromUtf8("/usr/測試")), QString::fromUtf8("測試"));
+    QCOMPARE(getBaseName(QString::fromUtf8("/√∆/測試")), QString::fromUtf8("測試"));
+}
+
+void FileUtils::expandUser() {
+    using::expandUser;
+    QCOMPARE(expandUser("~"), QDir::homePath() + "/");
+    QCOMPARE(expandUser("~/"), QDir::homePath() + "/");
+    QCOMPARE(expandUser("~//testuser"), QDir::homePath() + "//testuser");
+    QCOMPARE(expandUser("~/testuser"), QDir::home().filePath("testuser"));
+    QCOMPARE(expandUser("~/testuser/test1/test2"), QDir::home().filePath("testuser/test1/test2"));
+    QCOMPARE(expandUser("~testuser"), QFileInfo(QDir::homePath()).dir().filePath("testuser") + "/");
+    QCOMPARE(expandUser("~testuser//"), QFileInfo(QDir::homePath()).dir().filePath("testuser") + "//");
+    QCOMPARE(expandUser("~testuser/test1/test2/"), QFileInfo(QDir::homePath()).dir().filePath("testuser/test1/test2") + "/");
+}
+
+QTEST_APPLESS_MAIN(FileUtils)
+
diff --git a/tests/test_file-utils.h b/tests/test_file-utils.h
new file mode 100644 (file)
index 0000000..aa36dcd
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef TESTS_FILE_UTILS_H
+#define TESTS_FILE_UTILS_H
+#include <QObject>
+
+class FileUtils : public QObject {
+    Q_OBJECT
+public:
+    virtual ~FileUtils() {};
+
+private slots:
+    void getParentPath();
+    void getBaseName();
+    void expandUser();
+};
+
+#endif // TESTS_FILE_UTILS_H
+
diff --git a/tests/test_server-info.cpp b/tests/test_server-info.cpp
new file mode 100644 (file)
index 0000000..bb71349
--- /dev/null
@@ -0,0 +1,52 @@
+#include "test_server-info.h"
+#include <QSet>
+#include <QtTest/QtTest>
+
+#include "../src/api/server-info.h"
+
+void ServerInfoTest::testFeature() {
+    ServerInfo info1;
+    QString feature1 = "file-search,office-preview,seafile-pro";
+    info1.parseFeatureFromStrings(feature1.split(','));
+    QVERIFY(info1.proEdition);
+    QVERIFY(info1.fileSearch);
+    QVERIFY(info1.officePreview);
+    QSet<QString> info1_set = feature1.split(',').toSet();
+    QSet<QString> info1b_set = info1.getFeatureStrings().toSet();
+    QCOMPARE(info1_set, info1b_set);
+
+    ServerInfo info2;
+    QString feature2 = "file-search,seafile-pro";
+    info2.parseFeatureFromStrings(feature2.split(','));
+    QVERIFY(info2.proEdition);
+    QVERIFY(info2.fileSearch);
+    QVERIFY(!info2.officePreview);
+    QSet<QString> info2_set = feature2.split(',').toSet();
+    QSet<QString> info2b_set = info2.getFeatureStrings().toSet();
+    QCOMPARE(info2_set, info2b_set);
+
+    ServerInfo info3;
+    QString feature3 = "file-search,office-preview,seafile-pro";
+    info3.parseFeatureFromStrings(feature3.split(','));
+    QVERIFY(info3.proEdition);
+    QVERIFY(info3.fileSearch);
+    QVERIFY(info3.officePreview);
+    QSet<QString> info3_set = feature3.split(',').toSet();
+    QSet<QString> info3b_set = info3.getFeatureStrings().toSet();
+    QCOMPARE(info3_set, info3b_set);
+
+    info3.parseFeatureFromString("office-preview", false);
+    QVERIFY(!info3.officePreview);
+}
+
+void ServerInfoTest::testVersion() {
+    ServerInfo info;
+    QString version = "1.2.4";
+    info.parseVersionFromString(version);
+    QCOMPARE(info.majorVersion, 1u);
+    QCOMPARE(info.minorVersion, 2u);
+    QCOMPARE(info.patchVersion, 4u);
+    QCOMPARE(info.getVersionString(), version);
+}
+
+QTEST_APPLESS_MAIN(ServerInfoTest)
diff --git a/tests/test_server-info.h b/tests/test_server-info.h
new file mode 100644 (file)
index 0000000..3962e62
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef TESTS_SERVER_INFO_H
+#define TESTS_SERVER_INFO_H
+#include <QObject>
+
+class ServerInfoTest : public QObject {
+    Q_OBJECT
+public:
+    virtual ~ServerInfoTest() {};
+
+private slots:
+    void testFeature();
+    void testVersion();
+};
+
+#endif // TESTS_SERVER_INFO_H
+
diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp
new file mode 100644 (file)
index 0000000..2417291
--- /dev/null
@@ -0,0 +1,111 @@
+#include "test_stl.h"
+#include <QSet>
+#include <QtTest/QtTest>
+#include <vector>
+#include <cstring>
+#include <cwchar>
+
+#include "../src/utils/stl.h"
+
+void STLTest::testBufferArry() {
+  using utils::BufferArray;
+  // constructor
+  std::string test1("123456789abcdefg");
+  BufferArray buffer(test1);
+  QVERIFY(test1.size() + 1 == buffer.size());
+  QVERIFY(buffer.capacity() == buffer.size());
+  QVERIFY(strncmp(test1.data(), buffer.data(), test1.size()) == 0);
+
+  // operator[]
+  QVERIFY(test1[0] == '1');
+  QVERIFY(test1[1] == '2');
+  QVERIFY(test1[2] == '3');
+
+  // reserve
+  buffer.resize(30);
+  QVERIFY(buffer.capacity() == 30);
+
+  // shrink_to_fit
+  buffer.shrink_to_fit();
+  QVERIFY(buffer.capacity() == buffer.size());
+
+  // resize
+  buffer.resize(9);
+  std::string test2("12345678");
+  QVERIFY(test2.size() + 1 == buffer.size());
+  QVERIFY(buffer.capacity() > buffer.size());
+  QVERIFY(strncmp(test2.data(), buffer.data(), test2.size()) == 0);
+
+  // shrink_to_fit
+  buffer.shrink_to_fit();
+  QVERIFY(buffer.capacity() == buffer.size());
+
+#ifdef UTILS_CXX11_MODE
+  // move
+  std::string test3("gqjdiw913abc_123d");
+  BufferArray other_buffer(test3);
+  buffer = std::move(other_buffer);
+  QVERIFY(test3.size() + 1 == buffer.size());
+  QVERIFY(buffer.capacity() == buffer.size());
+  QVERIFY(strncmp(test3.data(), buffer.data(), test3.size()) == 0);
+
+  // constructor2
+  const char test_string[] = "abcdefg";
+  size_t test_size = sizeof(test_string);
+  buffer = BufferArray(test_string);
+  QVERIFY(test_size == buffer.size());
+  QVERIFY(buffer.capacity() == buffer.size());
+  QVERIFY(memcmp(test_string, buffer.data(), test_size) == 0);
+#endif
+}
+
+void STLTest::testWBufferArry() {
+  using utils::WBufferArray;
+  // constructor
+  std::wstring test1(L"123456789abcdefg");
+  WBufferArray buffer(test1);
+  QVERIFY(test1.size() + 1 == buffer.size());
+  QVERIFY(buffer.capacity() == buffer.size());
+  QVERIFY(wcsncmp(test1.data(), buffer.data(), test1.size()) == 0);
+
+  // operator[]
+  QVERIFY(test1[0] == L'1');
+  QVERIFY(test1[1] == L'2');
+  QVERIFY(test1[2] == L'3');
+
+  // reserve
+  buffer.resize(30);
+  QVERIFY(buffer.capacity() == 30);
+
+  // shrink_to_fit
+  buffer.shrink_to_fit();
+  QVERIFY(buffer.capacity() == buffer.size());
+
+  // resize
+  buffer.resize(9);
+  std::wstring test2(L"12345678");
+  QVERIFY(test2.size() + 1 == buffer.size());
+  QVERIFY(buffer.capacity() > buffer.size());
+  QVERIFY(wcsncmp(test2.data(), buffer.data(), test2.size()) == 0);
+
+#ifdef UTILS_CXX11_MODE
+  // move
+  std::wstring test3(L"gqjdiw913abc_123d");
+  WBufferArray other_buffer(test3);
+  buffer = std::move(other_buffer);
+  QVERIFY(test3.size() + 1 == buffer.size());
+  QVERIFY(buffer.capacity() == buffer.size());
+  QVERIFY(wcsncmp(test3.data(), buffer.data(), test3.size()) == 0);
+
+  // constructor2
+  const wchar_t test_string[] = L"abcdefg";
+  size_t test_size = sizeof(test_string) / sizeof(wchar_t);
+  buffer = WBufferArray(test_string);
+  QVERIFY(test_size == buffer.size());
+  QVERIFY(buffer.capacity() == buffer.size());
+  QVERIFY(memcmp(test_string, buffer.data(), test_size) == 0);
+#endif
+}
+
+
+QTEST_APPLESS_MAIN(STLTest)
diff --git a/tests/test_stl.h b/tests/test_stl.h
new file mode 100644 (file)
index 0000000..4462c9d
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef TESTS_STL_H
+#define TESTS_STL_H
+#include <QObject>
+
+class STLTest : public QObject {
+    Q_OBJECT
+public:
+    virtual ~STLTest() {};
+
+private slots:
+    void testBufferArry();
+    void testWBufferArry();
+};
+
+#endif // TESTS_STL_H
+
diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp
new file mode 100644 (file)
index 0000000..4de82a8
--- /dev/null
@@ -0,0 +1,105 @@
+#include "test_utils.h"
+#include <QtTest/QtTest>
+#include <algorithm>            // std::sort
+
+#include "../src/utils/utils.h"
+
+namespace {
+
+bool digitalCompareFileByName(const QString& a, const QString& b)
+{
+    return digitalCompare(a, b) < 0 ? true : false;
+}
+
+} // namespace
+
+void Utils::testReadableFileSize() {
+    QCOMPARE(::readableFileSize(0), QString("0B"));
+    QCOMPARE(::readableFileSize(1000), QString("1KB"));
+    QCOMPARE(::readableFileSize(1500), QString("2KB"));
+    QCOMPARE(::readableFileSize(1000000), QString("1.0MB"));
+    QCOMPARE(::readableFileSize(1230000), QString("1.2MB"));
+    QCOMPARE(::readableFileSize(1000 * 1000 * 1000), QString("1.0GB"));
+    QCOMPARE(::readableFileSize(1100 * 1000 * 1000), QString("1.1GB"));
+}
+
+
+void Utils::testIncludeUrlParams() {
+    QUrl urla(QString("http://example.com"));
+
+    QHash<QString, QString> params;
+    params.insert("simple", "c");
+    params.insert("withspecial", "a?b");
+    params.insert("withspace", "a b");
+    params.insert("username", "a123fx b");
+    params.insert("password", "!@#+-$%^12&*()qweqesaf\"';`~");
+    params.insert("withplus", "a+b");
+
+    QUrl urlb = ::includeQueryParams(urla, params);
+
+    QCOMPARE(urla.scheme(), urlb.scheme());
+    QCOMPARE(urla.host(), urlb.host());
+
+    Q_FOREACH (const QString& key, params.keys()) {
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+        QString encoded_key = QUrl::toPercentEncoding(key);
+        QString encoded_value = QUrl::toPercentEncoding(params[encoded_key]);
+        QUrlQuery query = QUrlQuery(urlb.query());
+        QCOMPARE(query.queryItemValue(encoded_key, QUrl::FullyEncoded), encoded_value);
+#else
+        QCOMPARE(urlb.queryItemValue(key), params[key]);
+#endif
+    }
+}
+
+void Utils::testDigitalCompare() {
+    QList<QString> list;
+    list << "05 copy 2.ico" << "05 copy 3.ico"
+         << "05 copy.ico" << "05.ico"
+         << "34th TOPIK Papers - Advanced level 2.pdf"
+         << "34th TOPIK Papers - Advanced level.pdf"
+         << "A1/" << "B1/" << "a2/" << "b2/"
+         << "IMG_20140523_171911 - 副本.jpg"
+         << "IMG_20140523_171911.jpg"
+         << "MIT18_06SCF11_Ses3.1sum.pdf" << "Paraffin.exe"
+         << "Screen Shot 2016-08-13 at 11.42.35 PM.png"
+         << "Screen Shot 2016-09-02 at 4.47.12 PM.png"
+         << "WixDependencyExtension.dll"
+         << "darice - 副本 - 副本.cub"
+         << "darice - 副本.cub" << "darice.cub"
+         << "depends.chm" << "depends.exe"
+         << "dokan-build - 副本.log" << "dokan-build.log"
+         << "dokan-build copy 2 - 副本(2).log"
+         << "dokan-build copy 2 - 副本.log"
+         << "dokan-build copy 2.log"
+         << "dokan-build copy 3.log"
+         << "dokan-build copy.log"
+         << "heat.exe" << "heat.exe.config"
+         << "new copy.txt" << "new.txt"
+         << "require(1).js" << "require.js"
+         << "subfolder1/" << "untitled folder/"
+         << "whole-stage-codegen.pdf" << "wix.dll"
+         << "x copy 10.md" << "x copy.md"
+         << "x copy 2.md" << "x copy 3.md"
+         << "新建文本文档.txt"
+         << "新建文本文档 copy.txt"
+         << "新建文本文档 - 副本.txt"
+         << "新建文本文档(2).txt"
+         << "新建文本文档(3).txt";
+    std::sort(list.begin(), list.end(), digitalCompareFileByName);
+
+    QCOMPARE(::digitalCompare("9", "9"), 0);
+    QCOMPARE(::digitalCompare("aa9aa", "aa9aa"), 0);
+    QCOMPARE(::digitalCompare("99a99", "99a99"), 0);
+    QCOMPARE(::digitalCompare("9", "11"), -2);
+    QCOMPARE(::digitalCompare("1.9", "1.11"), -2);
+    QCOMPARE(::digitalCompare("1 9", "1 11"), -2);
+    QCOMPARE(::digitalCompare("1abc1", "1abc1.abc"), -1);
+    QCOMPARE(::digitalCompare("1.1.1.1.9", "1.1.1.1.11"), -2);
+    QCOMPARE(::digitalCompare("a9", "a11"), -2);
+    QCOMPARE(::digitalCompare("a9aaa", "a11aaa"), -2);
+    QCOMPARE(::digitalCompare("zzz9", "bbb11"), QString::compare("zzz9", "bbb11"));
+    QCOMPARE(::digitalCompare("pp9p", "pa11a"), QString::compare("pp9p", "pa11a"));
+}
+
+QTEST_APPLESS_MAIN(Utils)
diff --git a/tests/test_utils.h b/tests/test_utils.h
new file mode 100644 (file)
index 0000000..1e7e921
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef TESTS_UTILS_H
+#define TESTS_UTILS_H
+#include <QObject>
+
+class Utils : public QObject {
+    Q_OBJECT
+public:
+    virtual ~Utils() {};
+
+private slots:
+    void testReadableFileSize();
+    void testIncludeUrlParams();
+    void testDigitalCompare();
+};
+
+#endif // TESTS_UTILS_H
+
diff --git a/third_party/QtAwesome/QtAwesome.cpp b/third_party/QtAwesome/QtAwesome.cpp
new file mode 100644 (file)
index 0000000..d610c72
--- /dev/null
@@ -0,0 +1,722 @@
+/**
+ * QtAwesome - use font-awesome (or other font icons) in your c++ / Qt Application
+ *
+ * Copyright 2013 - Reliable Bits Software by Blommers IT. All Rights Reserved.
+ * Author Rick Blommers
+ */
+
+#include "QtAwesome.h"
+
+#include <QDebug>
+#include <QFile>
+#include <QFontDatabase>
+
+
+/// The font-awesome icon painter
+class QtAwesomeCharIconPainter: public QtAwesomeIconPainter
+{
+public:
+    virtual void paint( QtAwesome* awesome, QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state, const QVariantMap& options  )
+    {
+        Q_UNUSED(mode);
+        Q_UNUSED(state);
+        Q_UNUSED(options);
+
+        painter->save();
+
+        // set the correct color
+        QColor color = options.value("color").value<QColor>();
+        QString text = options.value("text").toString();
+
+        if( mode == QIcon::Disabled ) {
+            color = options.value("color-disabled").value<QColor>();
+            QVariant alt = options.value("text-disabled");
+            if( alt.isValid() ) {
+                text = alt.toString();
+            }
+        } else if( mode == QIcon::Active ) {
+            color = options.value("color-active").value<QColor>();
+            QVariant alt = options.value("text-active");
+            if( alt.isValid() ) {
+                text = alt.toString();
+            }
+        } else if( mode == QIcon::Selected ) {
+            color = options.value("color-selected").value<QColor>();
+            QVariant alt = options.value("text-selected");
+            if( alt.isValid() ) {
+                text = alt.toString();
+            }
+        }
+        painter->setPen(color);
+
+        // add some 'padding' around the icon
+        int drawSize = qRound(rect.height()*options.value("scale-factor").toFloat());
+
+        painter->setFont( awesome->font(drawSize) );
+        painter->drawText( rect, text, QTextOption( Qt::AlignCenter|Qt::AlignVCenter ) );
+        painter->restore();
+    }
+
+};
+
+
+//---------------------------------------------------------------------------------------
+
+
+/// The painter icon engine.
+class QtAwesomeIconPainterIconEngine : public QIconEngine
+{
+
+public:
+
+    QtAwesomeIconPainterIconEngine( QtAwesome* awesome, QtAwesomeIconPainter* painter, const QVariantMap& options  )
+        : awesomeRef_(awesome)
+        , iconPainterRef_(painter)
+        , options_(options)
+    {
+    }
+
+    virtual ~QtAwesomeIconPainterIconEngine() {}
+
+    QtAwesomeIconPainterIconEngine* clone() const
+    {
+        return new QtAwesomeIconPainterIconEngine( awesomeRef_, iconPainterRef_, options_ );
+    }
+
+    virtual void paint(QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state)
+    {
+        Q_UNUSED( mode );
+        Q_UNUSED( state );
+        iconPainterRef_->paint( awesomeRef_, painter, rect, mode, state, options_ );
+    }
+
+    virtual QPixmap pixmap(const QSize& size, QIcon::Mode mode, QIcon::State state)
+    {
+        QPixmap pm(size);
+        pm.fill( Qt::transparent ); // we need transparency
+        {
+            QPainter p(&pm);
+            paint(&p, QRect(QPoint(0,0),size), mode, state);
+        }
+        return pm;
+    }
+
+private:
+
+    QtAwesome* awesomeRef_;                  ///< a reference to the QtAwesome instance
+    QtAwesomeIconPainter* iconPainterRef_;   ///< a reference to the icon painter
+    QVariantMap options_;                    ///< the options for this icon painter
+};
+
+
+//---------------------------------------------------------------------------------------
+
+/// The default icon colors
+QtAwesome::QtAwesome( QObject* parent )
+    : QObject( parent )
+    , namedCodepoints_()
+{
+    // initialize the default options
+    setDefaultOption( "color", QColor(50,50,50) );
+    setDefaultOption( "color-disabled", QColor(70,70,70,60));
+    setDefaultOption( "color-active", QColor(10,10,10));
+    setDefaultOption( "color-selected", QColor(10,10,10));
+    setDefaultOption( "scale-factor", 0.9 );
+
+    setDefaultOption( "text", QVariant() );
+    setDefaultOption( "text-disabled", QVariant() );
+    setDefaultOption( "text-active", QVariant() );
+    setDefaultOption( "text-selected", QVariant() );
+
+    fontIconPainter_ = new QtAwesomeCharIconPainter();
+
+}
+
+
+QtAwesome::~QtAwesome()
+{
+    delete fontIconPainter_;
+//    delete errorIconPainter_;
+    qDeleteAll(painterMap_);
+}
+
+/// initializes the QtAwesome icon factory with the given fontname
+void QtAwesome::init(const QString& fontname)
+{
+    fontName_ = fontname;
+}
+
+
+/// a specialized init function so font-awesome is loaded and initialized
+/// this method return true on success, it will return false if the fnot cannot be initialized
+/// To initialize QtAwesome with font-awesome you need to call this method
+bool QtAwesome::initFontAwesome( )
+{
+    static int fontAwesomeFontId = -1;
+    
+    // only load font-awesome once
+    if( fontAwesomeFontId < 0 ) {
+
+        // The macro below internally calls "qInitResources_QtAwesome()". this initializes
+        // the resource system. For a .pri project this isn't required, but when building and using a
+        // static library the resource need to initialized first.
+        ///
+        // I've checked th qInitResource_* code and calling this method mutliple times shouldn't be any problem
+        // (More info about this subject:  http://qt-project.org/wiki/QtResources)
+        Q_INIT_RESOURCE(QtAwesome);
+
+        // load the font file
+        QFile res(":/fonts/fontawesome.ttf");
+        if(!res.open(QIODevice::ReadOnly)) {
+            qDebug() << "Font awesome font could not be loaded!";
+            return false;
+        }
+        QByteArray fontData( res.readAll() );
+        res.close();
+
+        // fetch the given font
+        fontAwesomeFontId = QFontDatabase::addApplicationFontFromData(fontData);
+    }
+
+    QStringList loadedFontFamilies = QFontDatabase::applicationFontFamilies(fontAwesomeFontId);
+    if( !loadedFontFamilies.empty() ) {
+        fontName_= loadedFontFamilies.at(0);
+    } else {
+        qDebug() << "Font awesome font is empty?!";
+        fontAwesomeFontId = -1; // restore the font-awesome id
+        return false;
+    }
+
+    // intialize the map
+    QHash<QString, int>& m = namedCodepoints_;
+    m.insert( "glass",           icon_glass );
+    m.insert( "music",           icon_music );
+    m.insert( "search",          icon_search );
+    m.insert( "envelope",        icon_envelope );
+    m.insert( "heart",           icon_heart );
+    m.insert( "star",            icon_star );
+    m.insert( "star-empty",      icon_star_empty );
+    m.insert( "user",            icon_user );
+    m.insert( "film",            icon_film );
+    m.insert( "th-large",        icon_th_large );
+    m.insert( "th",              icon_th );
+    m.insert( "th-list",         icon_th_list );
+    m.insert( "ok",              icon_ok );
+    m.insert( "remove",          icon_remove );
+    m.insert( "zoom-in",         icon_zoom_in );
+
+    m.insert( "zoom-out",        icon_zoom_out );
+    m.insert( "off",             icon_off );
+    m.insert( "signal",          icon_signal );
+    m.insert( "cog",             icon_cog );
+    m.insert( "gear",            icon_gear );
+    m.insert( "trash",           icon_trash );
+    m.insert( "home",            icon_home );
+    m.insert( "file_alt",        icon_file_alt );
+    m.insert( "time",            icon_time );
+    m.insert( "road",            icon_road );
+    m.insert( "download-alt",    icon_download_alt );
+    m.insert( "download",        icon_download );
+    m.insert( "upload",          icon_upload );
+    m.insert( "inbox",           icon_inbox );
+    m.insert( "play-circle",     icon_play_circle );
+    m.insert( "repeat",          icon_repeat );
+
+    /* \f020 doesn't work in Safari. all shifted one down */
+
+
+    m.insert( "refresh",             icon_refresh );
+    m.insert( "list-alt",            icon_list_alt );
+    m.insert( "lock",                icon_lock );
+    m.insert( "flag",                icon_flag );
+    m.insert( "headphones",          icon_headphones );
+    m.insert( "volume-off",          icon_volume_off );
+    m.insert( "volume-down",         icon_volume_down );
+    m.insert( "volume-up",           icon_volume_up );
+    m.insert( "qrcode",              icon_qrcode );
+    m.insert( "barcode",             icon_barcode );
+    m.insert( "tag",                 icon_tag );
+    m.insert( "tags",                icon_tags );
+    m.insert( "book",                icon_book );
+    m.insert( "bookmark",            icon_bookmark );
+    m.insert( "print",               icon_print );
+
+    m.insert( "camera",              icon_camera );
+    m.insert( "font",                icon_font );
+    m.insert( "bold",                icon_bold );
+    m.insert( "italic",              icon_italic );
+    m.insert( "text-height",         icon_text_height );
+    m.insert( "text-width",          icon_text_width );
+    m.insert( "align-left",          icon_align_left );
+    m.insert( "align-center",        icon_align_center );
+    m.insert( "align-right",         icon_align_right );
+    m.insert( "align-justify",       icon_align_justify );
+    m.insert( "list",                icon_list );
+    m.insert( "indent-left",         icon_indent_left );
+    m.insert( "indent-right",        icon_indent_right );
+    m.insert( "facetime-video",      icon_facetime_video );
+    m.insert( "picture",             icon_picture );
+
+    m.insert( "pencil",               icon_pencil );
+    m.insert( "map-marker",           icon_map_marker );
+    m.insert( "adjust",               icon_adjust );
+    m.insert( "tint",                 icon_tint );
+    m.insert( "edit",                 icon_edit );
+    m.insert( "share",                icon_share );
+    m.insert( "check",                icon_check );
+    m.insert( "move",                 icon_move );
+    m.insert( "step-backward",        icon_step_backward );
+    m.insert( "fast-backward",        icon_fast_backward );
+    m.insert( "backward",             icon_backward );
+    m.insert( "play",                 icon_play );
+    m.insert( "pause",                icon_pause );
+    m.insert( "stop",                 icon_stop );
+    m.insert( "forward",              icon_forward );
+
+    m.insert( "fast-forward",         icon_fast_forward );
+    m.insert( "step-forward",         icon_step_forward );
+    m.insert( "eject",                icon_eject );
+    m.insert( "chevron-left",         icon_chevron_left );
+    m.insert( "chevron-right",        icon_chevron_right );
+    m.insert( "plus-sign",            icon_plus_sign );
+    m.insert( "minus-sign",           icon_minus_sign );
+    m.insert( "remove-sign",          icon_remove_sign );
+    m.insert( "ok-sign",              icon_ok_sign );
+    m.insert( "question-sign",        icon_question_sign );
+    m.insert( "info-sign",            icon_info_sign );
+    m.insert( "screenshot",           icon_screenshot );
+    m.insert( "remove-circle",        icon_remove_circle );
+    m.insert( "ok-circle",            icon_ok_circle );
+    m.insert( "ban-circle",           icon_ban_circle );
+
+    m.insert( "arrow-left",           icon_arrow_left );
+    m.insert( "arrow-right",          icon_arrow_right );
+    m.insert( "arrow-up",             icon_arrow_up );
+    m.insert( "arrow-down",           icon_arrow_down );
+    m.insert( "share-alt",            icon_share_alt );
+    m.insert( "resize-full",          icon_resize_full );
+    m.insert( "resize-small",         icon_resize_small );
+    m.insert( "plus",                 icon_plus );
+    m.insert( "minus",                icon_minus );
+    m.insert( "asterisk",             icon_asterisk );
+    m.insert( "exclamation-sign",     icon_exclamation_sign );
+    m.insert( "gift",                 icon_gift );
+    m.insert( "leaf",                 icon_leaf );
+    m.insert( "fire",                 icon_fire );
+    m.insert( "eye-open",             icon_eye_open );
+
+    m.insert( "eye-close",            icon_eye_close );
+    m.insert( "warning-sign",         icon_warning_sign );
+    m.insert( "plane",                icon_plane );
+    m.insert( "calendar",             icon_calendar );
+    m.insert( "random",               icon_random );
+    m.insert( "comment",              icon_comment );
+    m.insert( "magnet",               icon_magnet );
+    m.insert( "chevron-up",           icon_chevron_up );
+    m.insert( "chevron-down",         icon_chevron_down );
+    m.insert( "retweet",              icon_retweet );
+    m.insert( "shopping-cart",        icon_shopping_cart );
+    m.insert( "folder-close",         icon_folder_close );
+    m.insert( "folder-open",          icon_folder_open );
+    m.insert( "resize-vertical",      icon_resize_vertical );
+    m.insert( "resize-horizontal",    icon_resize_horizontal );
+
+    m.insert( "bar-chart",            icon_bar_chart );
+    m.insert( "twitter-sign",         icon_twitter_sign );
+    m.insert( "facebook-sign",        icon_facebook_sign );
+    m.insert( "camera-retro",         icon_camera_retro );
+    m.insert( "key",                  icon_key );
+    m.insert( "cogs",                 icon_cogs );
+    m.insert( "gears",                icon_gears );
+    m.insert( "comments",             icon_comments );
+    m.insert( "thumbs-up-alt",        icon_thumbs_up_alt );
+    m.insert( "thumbs-down-alt",      icon_thumbs_down_alt );
+    m.insert( "star-half",            icon_star_half );
+    m.insert( "heart-empty",          icon_heart_empty );
+    m.insert( "signout",              icon_signout );
+    m.insert( "linkedin-sign",        icon_linkedin_sign );
+    m.insert( "pushpin",              icon_pushpin );
+    m.insert( "external-link",        icon_external_link );
+
+    m.insert( "signin",               icon_signin );
+    m.insert( "trophy",               icon_trophy );
+    m.insert( "github-sign",          icon_github_sign );
+    m.insert( "upload-alt",           icon_upload_alt );
+    m.insert( "lemon",                icon_lemon );
+    m.insert( "phone",                icon_phone );
+    m.insert( "check-empty",          icon_check_empty );
+    m.insert( "bookmark-empty",       icon_bookmark_empty );
+    m.insert( "phone-sign",           icon_phone_sign );
+    m.insert( "twitter",              icon_twitter );
+    m.insert( "facebook",             icon_facebook );
+    m.insert( "github",               icon_github );
+    m.insert( "unlock",               icon_unlock );
+    m.insert( "credit-card",          icon_credit_card );
+    m.insert( "rss",                  icon_rss );
+
+    m.insert( "hdd",                  icon_hdd );
+    m.insert( "bullhorn",             icon_bullhorn );
+    m.insert( "bell",                 icon_bell );
+    m.insert( "certificate",          icon_certificate );
+    m.insert( "hand-right",           icon_hand_right );
+    m.insert( "hand-left",            icon_hand_left );
+    m.insert( "hand-up",              icon_hand_up );
+    m.insert( "hand-down",            icon_hand_down );
+    m.insert( "circle-arrow-left",    icon_circle_arrow_left );
+    m.insert( "circle-arrow-right",   icon_circle_arrow_right );
+    m.insert( "circle-arrow-up",      icon_circle_arrow_up );
+    m.insert( "circle-arrow-down",    icon_circle_arrow_down );
+    m.insert( "globe",                icon_globe );
+    m.insert( "wrench",               icon_wrench );
+    m.insert( "tasks",                icon_tasks );
+
+    m.insert( "filter",               icon_filter );
+    m.insert( "briefcase",            icon_briefcase );
+    m.insert( "fullscreen",           icon_fullscreen );
+
+    m.insert( "group",                icon_group );
+    m.insert( "link",                 icon_link );
+    m.insert( "cloud",                icon_cloud );
+    m.insert( "beaker",               icon_beaker );
+    m.insert( "cut",                  icon_cut );
+    m.insert( "copy",                 icon_copy );
+    m.insert( "paper-clip",           icon_paper_clip );
+    m.insert( "save",                 icon_save );
+    m.insert( "sign-blank",           icon_sign_blank );
+    m.insert( "reorder",              icon_reorder );
+    m.insert( "list-ul",              icon_list_ul );
+    m.insert( "list-ol",              icon_list_ol );
+    m.insert( "strikethrough",        icon_strikethrough );
+    m.insert( "underline",            icon_underline );
+    m.insert( "table",                icon_table );
+
+    m.insert( "magic",                icon_magic );
+    m.insert( "truck",                icon_truck );
+    m.insert( "pinterest",            icon_pinterest );
+    m.insert( "pinterest-sign",       icon_pinterest_sign );
+    m.insert( "google-plus-sign",     icon_google_plus_sign );
+    m.insert( "google-plus",          icon_google_plus );
+    m.insert( "money",                icon_money );
+    m.insert( "caret-down",           icon_caret_down );
+    m.insert( "caret-up",             icon_caret_up );
+    m.insert( "caret-left",           icon_caret_left );
+    m.insert( "caret-right",          icon_caret_right );
+    m.insert( "columns",              icon_columns );
+    m.insert( "sort",                 icon_sort );
+    m.insert( "sort-down",            icon_sort_down );
+    m.insert( "sort-up",              icon_sort_up );
+
+    m.insert( "envelope-alt",         icon_envelope_alt );
+    m.insert( "linkedin",             icon_linkedin );
+    m.insert( "undo",                 icon_undo );
+    m.insert( "legal",                icon_legal );
+    m.insert( "dashboard",            icon_dashboard );
+    m.insert( "comment-alt",          icon_comment_alt );
+    m.insert( "comments-alt",         icon_comments_alt );
+    m.insert( "bolt",                 icon_bolt );
+    m.insert( "sitemap",              icon_sitemap );
+    m.insert( "umbrella",             icon_umbrella );
+    m.insert( "paste",                icon_paste );
+    m.insert( "lightbulb",            icon_lightbulb );
+    m.insert( "exchange",             icon_exchange );
+    m.insert( "cloud-download",       icon_cloud_download );
+    m.insert( "cloud-upload",         icon_cloud_upload );
+
+    m.insert( "user-md",              icon_user_md );
+    m.insert( "stethoscope",          icon_stethoscope );
+    m.insert( "suitcase",             icon_suitcase );
+    m.insert( "bell-alt",             icon_bell_alt );
+    m.insert( "coffee",               icon_coffee );
+    m.insert( "food",                 icon_food );
+    m.insert( "file-text-alt",        icon_file_text_alt );
+    m.insert( "building",             icon_building );
+    m.insert( "hospital",             icon_hospital );
+    m.insert( "ambulance",            icon_ambulance );
+    m.insert( "medkit",               icon_medkit );
+    m.insert( "fighter-jet",          icon_fighter_jet );
+    m.insert( "beer",                 icon_beer );
+    m.insert( "h-sign",               icon_h_sign );
+    m.insert( "plus-sign-alt",        icon_plus_sign_alt );
+
+    m.insert( "double-angle-left",    icon_double_angle_left );
+    m.insert( "double-angle-right",   icon_double_angle_right );
+    m.insert( "double-angle-up",      icon_double_angle_up );
+    m.insert( "double-angle-down",    icon_double_angle_down );
+    m.insert( "angle-left",           icon_angle_left );
+    m.insert( "angle-right",          icon_angle_right );
+    m.insert( "angle-up",             icon_angle_up );
+    m.insert( "angle-down",           icon_angle_down );
+    m.insert( "desktop",              icon_desktop );
+    m.insert( "laptop",               icon_laptop );
+    m.insert( "tablet",               icon_tablet );
+    m.insert( "mobile-phone",         icon_mobile_phone );
+    m.insert( "circle-blank",         icon_circle_blank );
+    m.insert( "quote-left",           icon_quote_left );
+    m.insert( "quote-right",          icon_quote_right );
+
+    m.insert( "spinner",              icon_spinner );
+    m.insert( "circle",               icon_circle );
+    m.insert( "reply",                icon_reply );
+    m.insert( "mail_reply",           icon_mail_reply );
+
+    m.insert( "github-alt",           icon_github_alt );
+    m.insert( "folder-close-alt",     icon_folder_close_alt );
+    m.insert( "folder-open-alt",      icon_folder_open_alt );
+
+    m.insert( "expand_alt",      icon_expand_alt );
+    m.insert( "collapse_alt",    icon_collapse_alt );
+    m.insert( "smile",           icon_smile );
+    m.insert( "frown",           icon_frown );
+    m.insert( "meh",             icon_meh );
+    m.insert( "gamepad",         icon_gamepad );
+    m.insert( "keyboard",        icon_keyboard );
+    m.insert( "flag_alt",        icon_flag_alt );
+    m.insert( "flag_checkered",  icon_flag_checkered );
+
+    m.insert( "terminal",        icon_terminal );
+    m.insert( "code",            icon_code );
+    m.insert( "reply_all",       icon_reply_all );
+    m.insert( "mail_reply_all",  icon_mail_reply_all );
+    m.insert( "star_half_full",  icon_star_half_full );
+    m.insert( "star_half_empty", icon_star_half_empty );
+    m.insert( "location_arrow",  icon_location_arrow );
+    m.insert( "crop",            icon_crop );
+    m.insert( "code_fork",       icon_code_fork );
+    m.insert( "unlink",          icon_unlink );
+    m.insert( "question",        icon_question );
+    m.insert( "info",            icon_info );
+    m.insert( "exclamation",     icon_exclamation );
+    m.insert( "superscript",     icon_superscript );
+    m.insert( "subscript",       icon_subscript );
+    m.insert( "eraser",          icon_eraser );
+    m.insert( "puzzle_piece",    icon_puzzle_piece );
+
+    m.insert( "microphone",         icon_microphone );
+    m.insert( "microphone_off",     icon_microphone_off );
+    m.insert( "shield",             icon_shield );
+    m.insert( "calendar_empty",     icon_calendar_empty );
+    m.insert( "fire_extinguisher",  icon_fire_extinguisher );
+    m.insert( "rocket",             icon_rocket );
+    m.insert( "maxcdn",             icon_maxcdn );
+    m.insert( "chevron_sign_left",  icon_chevron_sign_left );
+    m.insert( "chevron_sign_right", icon_chevron_sign_right );
+    m.insert( "chevron_sign_up",    icon_chevron_sign_up );
+    m.insert( "chevron_sign_down",  icon_chevron_sign_down );
+    m.insert( "html5",              icon_html5 );
+    m.insert( "css3",               icon_css3 );
+    m.insert( "anchor",             icon_anchor );
+    m.insert( "unlock_alt",         icon_unlock_alt );
+
+    m.insert( "bullseye",            icon_bullseye );
+    m.insert( "ellipsis_horizontal", icon_ellipsis_horizontal );
+    m.insert( "ellipsis_vertical",   icon_ellipsis_vertical );
+    m.insert( "rss_sign",            icon_rss_sign );
+    m.insert( "play_sign",           icon_play_sign );
+    m.insert( "ticket",              icon_ticket );
+    m.insert( "minus_sign_alt",      icon_minus_sign_alt );
+    m.insert( "check_minus",         icon_check_minus );
+    m.insert( "level_up",            icon_level_up );
+    m.insert( "level_down",          icon_level_down );
+    m.insert( "check_sign",          icon_check_sign );
+    m.insert( "edit_sign",           icon_edit_sign );
+    m.insert( "external_link_sign",  icon_external_link_sign );
+    m.insert( "share_sign",          icon_share_sign );
+
+    // v3.2.0
+    m.insert( "compass",    icon_compass );
+
+    m.insert( "collapse",               icon_collapse );
+    m.insert( "collapse_top",           icon_collapse_top );
+    m.insert( "expand",                 icon_expand );
+    m.insert( "euro",                   icon_euro );
+    m.insert( "eur",                    icon_eur );
+    m.insert( "gbp",                    icon_gbp );
+    m.insert( "dollar",                 icon_dollar );
+    m.insert( "usd",                    icon_usd );
+    m.insert( "rupee",                  icon_rupee );
+    m.insert( "inr",                    icon_inr );
+    m.insert( "yen",                    icon_yen );
+    m.insert( "jpy",                    icon_jpy );
+    m.insert( "renminbi",               icon_renminbi );
+    m.insert( "cny",                    icon_cny );
+    m.insert( "won",                    icon_won );
+    m.insert( "krw",                    icon_krw );
+    m.insert( "bitcoin",                icon_bitcoin );
+    m.insert( "btc",                    icon_btc );
+    m.insert( "file",                   icon_file );
+    m.insert( "file_text",              icon_file_text );
+    m.insert( "sort_by_alphabet",       icon_sort_by_alphabet );
+    m.insert( "sort_by_alphabet_alt",   icon_sort_by_alphabet_alt );
+    m.insert( "sort_by_attributes",     icon_sort_by_attributes );
+    m.insert( "sort_by_attributes_alt", icon_sort_by_attributes_alt );
+
+    m.insert( "sort_by_order",     icon_sort_by_order );
+    m.insert( "sort_by_order_alt", icon_sort_by_order_alt );
+    m.insert( "thumbs_up",         icon_thumbs_up );
+    m.insert( "thumbs_down",       icon_thumbs_down );
+    m.insert( "youtube_sign",      icon_youtube_sign );
+    m.insert( "youtube",           icon_youtube );
+    m.insert( "xing",              icon_xing );
+    m.insert( "xing_sign",         icon_xing_sign );
+    m.insert( "youtube_play",      icon_youtube_play );
+    m.insert( "dropbox",           icon_dropbox );
+    m.insert( "stackexchange",     icon_stackexchange );
+    m.insert( "instagram",         icon_instagram );
+    m.insert( "flickr",            icon_flickr );
+
+    m.insert( "adn",              icon_adn );
+    m.insert( "bitbucket",        icon_bitbucket );
+    m.insert( "bitbucket_sign",   icon_bitbucket_sign );
+    m.insert( "tumblr",           icon_tumblr );
+    m.insert( "tumblr_sign",      icon_tumblr_sign );
+    m.insert( "long_arrow_down",  icon_long_arrow_down );
+    m.insert( "long_arrow_up",    icon_long_arrow_up );
+    m.insert( "long_arrow_left",  icon_long_arrow_left );
+    m.insert( "long_arrow_right", icon_long_arrow_right );
+    m.insert( "apple",            icon_apple );
+    m.insert( "windows",          icon_windows );
+    m.insert( "android",          icon_android );
+    m.insert( "linux",            icon_linux );
+    m.insert( "dribble",          icon_dribble );
+    m.insert( "skype",            icon_skype );
+
+    m.insert( "foursquare", icon_foursquare );
+    m.insert( "trello",     icon_trello );
+    m.insert( "female",     icon_female );
+    m.insert( "male",       icon_male );
+    m.insert( "gittip",     icon_gittip );
+    m.insert( "sun",        icon_sun );
+    m.insert( "moon",       icon_moon );
+    m.insert( "archive",    icon_archive );
+    m.insert( "bug",        icon_bug );
+    m.insert( "vk",         icon_vk );
+    m.insert( "weibo",      icon_weibo );
+    m.insert( "renren",     icon_renren );
+
+    m.insert( "circle_close",     icon_circle_close );
+
+    return true;
+}
+
+void QtAwesome::addNamedCodepoint( const QString& name, int codePoint)
+{
+    namedCodepoints_.insert( name, codePoint);
+}
+
+
+/// Sets a default option. These options are passed on to the icon painters
+void QtAwesome::setDefaultOption(const QString& name, const QVariant& value)
+{
+    defaultOptions_.insert( name, value );
+}
+
+
+/// Returns the default option for the given name
+QVariant QtAwesome::defaultOption(const QString& name)
+{
+    return defaultOptions_.value( name );
+}
+
+
+// internal helper method to merge to option amps
+static QVariantMap mergeOptions( const QVariantMap& defaults, const QVariantMap& override )
+{
+    QVariantMap result= defaults;
+    if( !override.isEmpty() ) {
+        QMapIterator<QString,QVariant> itr(override);
+        while( itr.hasNext() ) {
+            itr.next();
+            result.insert( itr.key(), itr.value() );
+        }
+    }
+    return result;
+}
+
+
+/// Creates an icon with the given code-point
+/// <code>
+///     awesome->icon( icon_group )
+/// </code>
+QIcon QtAwesome::icon(int character, const QVariantMap &options)
+{
+    // create a merged QVariantMap to have default options and icon-specific options
+    QVariantMap optionMap = mergeOptions( defaultOptions_, options );
+    optionMap.insert("text", QString( QChar(character) ) );
+
+    return icon( fontIconPainter_, optionMap );
+}
+
+
+
+/// Creates an icon with the given name
+///
+/// You can use the icon names as defined on http://fortawesome.github.io/Font-Awesome/design.html  withour the 'icon-' prefix
+/// @param name the name of the icon
+/// @param options extra option to pass to the icon renderer
+QIcon QtAwesome::icon(const QString& name, const QVariantMap& options)
+{
+    // when it's a named codepoint
+    if( namedCodepoints_.count(name) ) {
+        return icon( namedCodepoints_.value(name), options );
+    }
+
+
+    // create a merged QVariantMap to have default options and icon-specific options
+    QVariantMap optionMap = mergeOptions( defaultOptions_, options );
+
+    // this method first tries to retrieve the icon
+    QtAwesomeIconPainter* painter = painterMap_.value(name);
+    if( !painter ) {
+        return QIcon();
+    }
+
+    return icon( painter, optionMap );
+}
+
+/// Create a dynamic icon by simlpy supplying a painter object
+/// The ownership of the painter is NOT transfered.
+/// @param painter a dynamic painter that is going to paint the icon
+/// @param optionmap the options to pass to the painter
+QIcon QtAwesome::icon(QtAwesomeIconPainter* painter, const QVariantMap& optionMap )
+{
+    // Warning, when you use memoryleak detection. You should turn it of for the next call
+    // QIcon's placed in gui items are often cached and not deleted when my memory-leak detection checks for leaks.
+    // I'm not sure if it's a Qt bug or something I do wrong
+    QtAwesomeIconPainterIconEngine* engine = new QtAwesomeIconPainterIconEngine( this, painter, optionMap  );
+    return QIcon( engine );
+}
+
+QIcon QtAwesome::icon(int character, const QColor& color)
+{
+    QVariantMap optionMap;
+    optionMap.insert("color", color);
+    optionMap.insert("color-disabled", color);
+    optionMap.insert("color-active", color);
+    optionMap.insert("color-selected", color);
+    return icon(character, optionMap);
+}
+
+/// Adds a named icon-painter to the QtAwesome icon map
+/// As the name applies the ownership is passed over to QtAwesome
+///
+/// @param name the name of the icon
+/// @param painter the icon painter to add for this name
+void QtAwesome::give(const QString& name, QtAwesomeIconPainter* painter)
+{
+    delete painterMap_.value( name );   // delete the old one
+    painterMap_.insert( name, painter );
+}
+
+/// Creates/Gets the icon font with a given size in pixels. This can be usefull to use a label for displaying icons
+/// Example:
+///
+///    QLabel* label = new QLabel( QChar( icon_group ) );
+///    label->setFont( awesome->font(16) )
+QFont QtAwesome::font( int size )
+{
+    QFont font( fontName_);
+    font.setPixelSize(size);
+    return font;
+}
+
+QtAwesome *awesome;
diff --git a/third_party/QtAwesome/QtAwesome.h b/third_party/QtAwesome/QtAwesome.h
new file mode 100644 (file)
index 0000000..07d94fd
--- /dev/null
@@ -0,0 +1,487 @@
+/**
+ * QtAwesome - use font-awesome (or other font icons) in your c++ / Qt Application
+ *
+ * Copyright 2013 - Reliable Bits Software by Blommers IT. All Rights Reserved.
+ * Author Rick Blommers
+ */
+
+#ifndef QTAWESOME_H
+#define QTAWESOME_H
+
+#include <QIcon>
+#include <QIconEngine>
+#include <QPainter>
+#include <QRect>
+#include <QVariantMap>
+
+
+/// A list of all icon-names with the codepoint (unicode-value) on the right
+/// You can use the names on the page  http://fortawesome.github.io/Font-Awesome/design.html  ( replace every dash '-' with an underscore '_')
+enum QtFontAwesomeName {
+    icon_glass               = 0xf000,
+    icon_music               = 0xf001,
+    icon_search              = 0xf002,
+    icon_envelope            = 0xf003,
+    icon_heart               = 0xf004,
+    icon_star                = 0xf005,
+    icon_star_empty          = 0xf006,
+    icon_user                = 0xf007,
+    icon_film                = 0xf008,
+    icon_th_large            = 0xf009,
+    icon_th                  = 0xf00a,
+    icon_th_list             = 0xf00b,
+    icon_ok                  = 0xf00c,
+    icon_remove              = 0xf00d,
+    icon_zoom_in             = 0xf00e,
+
+    icon_zoom_out            = 0xf010,
+    icon_off                 = 0xf011,
+    icon_signal              = 0xf012,
+    icon_cog                 = 0xf013,
+    icon_gear                = icon_cog,
+    icon_trash               = 0xf014,
+    icon_home                = 0xf015,
+    icon_file_alt            = 0xf016,
+    icon_time                = 0xf017,
+    icon_road                = 0xf018,
+    icon_download_alt        = 0xf019,
+    icon_download            = 0xf01a,
+    icon_upload              = 0xf01b,
+    icon_inbox               = 0xf01c,
+    icon_play_circle         = 0xf01d,
+    icon_repeat              = 0xf01e,
+
+    /* \f020 doesn't work in Safari. all shifted one down */
+    icon_refresh             = 0xf021,
+    icon_list_alt            = 0xf022,
+    icon_lock                = 0xf023,
+    icon_flag                = 0xf024,
+    icon_headphones          = 0xf025,
+    icon_volume_off          = 0xf026,
+    icon_volume_down         = 0xf027,
+    icon_volume_up           = 0xf028,
+    icon_qrcode              = 0xf029,
+    icon_barcode             = 0xf02a,
+    icon_tag                 = 0xf02b,
+    icon_tags                = 0xf02c,
+    icon_book                = 0xf02d,
+    icon_bookmark            = 0xf02e,
+    icon_print               = 0xf02f,
+
+    icon_camera              = 0xf030,
+    icon_font                = 0xf031,
+    icon_bold                = 0xf032,
+    icon_italic              = 0xf033,
+    icon_text_height         = 0xf034,
+    icon_text_width          = 0xf035,
+    icon_align_left          = 0xf036,
+    icon_align_center        = 0xf037,
+    icon_align_right         = 0xf038,
+    icon_align_justify       = 0xf039,
+    icon_list                = 0xf03a,
+    icon_indent_left         = 0xf03b,
+    icon_indent_right        = 0xf03c,
+    icon_facetime_video      = 0xf03d,
+    icon_picture             = 0xf03e,
+
+    icon_pencil              = 0xf040,
+    icon_map_marker          = 0xf041,
+    icon_adjust              = 0xf042,
+    icon_tint                = 0xf043,
+    icon_edit                = 0xf044,
+    icon_share               = 0xf045,
+    icon_check               = 0xf046,
+    icon_move                = 0xf047,
+    icon_step_backward       = 0xf048,
+    icon_fast_backward       = 0xf049,
+    icon_backward            = 0xf04a,
+    icon_play                = 0xf04b,
+    icon_pause               = 0xf04c,
+    icon_stop                = 0xf04d,
+    icon_forward             = 0xf04e,
+
+    icon_fast_forward        = 0xf050,
+    icon_step_forward        = 0xf051,
+    icon_eject               = 0xf052,
+    icon_chevron_left        = 0xf053,
+    icon_chevron_right       = 0xf054,
+    icon_plus_sign           = 0xf055,
+    icon_minus_sign          = 0xf056,
+    icon_remove_sign         = 0xf057,
+    icon_ok_sign             = 0xf058,
+    icon_question_sign       = 0xf059,
+    icon_info_sign           = 0xf05a,
+    icon_screenshot          = 0xf05b,
+    icon_remove_circle       = 0xf05c,
+    icon_ok_circle           = 0xf05d,
+    icon_ban_circle          = 0xf05e,
+
+    icon_arrow_left          = 0xf060,
+    icon_arrow_right         = 0xf061,
+    icon_arrow_up            = 0xf062,
+    icon_arrow_down          = 0xf063,
+    icon_share_alt           = 0xf064,
+    icon_resize_full         = 0xf065,
+    icon_resize_small        = 0xf066,
+    icon_plus                = 0xf067,
+    icon_minus               = 0xf068,
+    icon_asterisk            = 0xf069,
+    icon_exclamation_sign    = 0xf06a,
+    icon_gift                = 0xf06b,
+    icon_leaf                = 0xf06c,
+    icon_fire                = 0xf06d,
+    icon_eye_open            = 0xf06e,
+
+    icon_eye_close           = 0xf070,
+    icon_warning_sign        = 0xf071,
+    icon_plane               = 0xf072,
+    icon_calendar            = 0xf073,
+    icon_random              = 0xf074,
+    icon_comment             = 0xf075,
+    icon_magnet              = 0xf076,
+    icon_chevron_up          = 0xf077,
+    icon_chevron_down        = 0xf078,
+    icon_retweet             = 0xf079,
+    icon_shopping_cart       = 0xf07a,
+    icon_folder_close        = 0xf07b,
+    icon_folder_open         = 0xf07c,
+    icon_resize_vertical     = 0xf07d,
+    icon_resize_horizontal   = 0xf07e,
+
+    icon_bar_chart           = 0xf080,
+    icon_twitter_sign        = 0xf081,
+    icon_facebook_sign       = 0xf082,
+    icon_camera_retro        = 0xf083,
+    icon_key                 = 0xf084,
+    icon_cogs                = 0xf085,
+    icon_gears               = icon_cogs,
+    icon_comments            = 0xf086,
+    icon_thumbs_up_alt       = 0xf087,
+    icon_thumbs_down_alt     = 0xf088,
+    icon_star_half           = 0xf089,
+    icon_heart_empty         = 0xf08a,
+    icon_signout             = 0xf08b,
+    icon_linkedin_sign       = 0xf08c,
+    icon_pushpin             = 0xf08d,
+    icon_external_link       = 0xf08e,
+
+    icon_signin              = 0xf090,
+    icon_trophy              = 0xf091,
+    icon_github_sign         = 0xf092,
+    icon_upload_alt          = 0xf093,
+    icon_lemon               = 0xf094,
+    icon_phone               = 0xf095,
+    icon_check_empty         = 0xf096,
+    icon_bookmark_empty      = 0xf097,
+    icon_phone_sign          = 0xf098,
+    icon_twitter             = 0xf099,
+    icon_facebook            = 0xf09a,
+    icon_github              = 0xf09b,
+    icon_unlock              = 0xf09c,
+    icon_credit_card         = 0xf09d,
+    icon_rss                 = 0xf09e,
+
+    icon_hdd                 = 0xf0a0,
+    icon_bullhorn            = 0xf0a1,
+    icon_bell                = 0xf0a2,
+    icon_certificate         = 0xf0a3,
+    icon_hand_right          = 0xf0a4,
+    icon_hand_left           = 0xf0a5,
+    icon_hand_up             = 0xf0a6,
+    icon_hand_down           = 0xf0a7,
+    icon_circle_arrow_left   = 0xf0a8,
+    icon_circle_arrow_right  = 0xf0a9,
+    icon_circle_arrow_up     = 0xf0aa,
+    icon_circle_arrow_down   = 0xf0ab,
+    icon_globe               = 0xf0ac,
+    icon_wrench              = 0xf0ad,
+    icon_tasks               = 0xf0ae,
+
+    icon_filter              = 0xf0b0,
+    icon_briefcase           = 0xf0b1,
+    icon_fullscreen          = 0xf0b2,
+
+    icon_group               = 0xf0c0,
+    icon_link                = 0xf0c1,
+    icon_cloud               = 0xf0c2,
+    icon_beaker              = 0xf0c3,
+    icon_cut                 = 0xf0c4,
+    icon_copy                = 0xf0c5,
+    icon_paper_clip          = 0xf0c6,
+    icon_save                = 0xf0c7,
+    icon_sign_blank          = 0xf0c8,
+    icon_reorder             = 0xf0c9,
+    icon_list_ul             = 0xf0ca,
+    icon_list_ol             = 0xf0cb,
+    icon_strikethrough       = 0xf0cc,
+    icon_underline           = 0xf0cd,
+    icon_table               = 0xf0ce,
+
+    icon_magic               = 0xf0d0,
+    icon_truck               = 0xf0d1,
+    icon_pinterest           = 0xf0d2,
+    icon_pinterest_sign      = 0xf0d3,
+    icon_google_plus_sign    = 0xf0d4,
+    icon_google_plus         = 0xf0d5,
+    icon_money               = 0xf0d6,
+    icon_caret_down          = 0xf107,
+    icon_caret_up            = 0xf106,
+    icon_caret_left          = 0xf104,
+    icon_caret_right         = 0xf105,
+    icon_columns             = 0xf0db,
+    icon_sort                = 0xf0dc,
+    icon_sort_down           = 0xf0dd,
+    icon_sort_up             = 0xf0de,
+
+    icon_envelope_alt        = 0xf0e0,
+    icon_linkedin            = 0xf0e1,
+    icon_undo                = 0xf0e2,
+    icon_legal               = 0xf0e3,
+    icon_dashboard           = 0xf0e4,
+    icon_comment_alt         = 0xf0e5,
+    icon_comments_alt        = 0xf0e6,
+    icon_bolt                = 0xf0e7,
+    icon_sitemap             = 0xf0e8,
+    icon_umbrella            = 0xf0e9,
+    icon_paste               = 0xf0ea,
+    icon_lightbulb           = 0xf0eb,
+    icon_exchange            = 0xf0ec,
+    icon_cloud_download      = 0xf0ed,
+    icon_cloud_upload        = 0xf0ee,
+
+    icon_user_md             = 0xf0f0,
+    icon_stethoscope         = 0xf0f1,
+    icon_suitcase            = 0xf0f2,
+    icon_bell_alt            = 0xf0f3,
+    icon_coffee              = 0xf0f4,
+    icon_food                = 0xf0f5,
+    icon_file_text_alt       = 0xf0f6,
+    icon_building            = 0xf0f7,
+    icon_hospital            = 0xf0f8,
+    icon_ambulance           = 0xf0f9,
+    icon_medkit              = 0xf0fa,
+    icon_fighter_jet         = 0xf0fb,
+    icon_beer                = 0xf0fc,
+    icon_h_sign              = 0xf0fd,
+    icon_plus_sign_alt       = 0xf0fe,
+
+    icon_double_angle_left   = 0xf100,
+    icon_double_angle_right  = 0xf101,
+    icon_double_angle_up     = 0xf102,
+    icon_double_angle_down   = 0xf103,
+    icon_angle_left          = 0xf104,
+    icon_angle_right         = 0xf105,
+    icon_angle_up            = 0xf106,
+    icon_angle_down          = 0xf107,
+    icon_desktop             = 0xf108,
+    icon_laptop              = 0xf109,
+    icon_tablet              = 0xf10a,
+    icon_mobile_phone        = 0xf10b,
+    icon_circle_blank        = 0xf10c,
+    icon_quote_left          = 0xf10d,
+    icon_quote_right         = 0xf10e,
+
+    icon_spinner             = 0xf110,
+    icon_circle              = 0xf111,
+    icon_mail_reply          = 0xf112,
+    icon_reply               = icon_mail_reply,
+
+    icon_github_alt          = 0xf113,
+    icon_folder_close_alt    = 0xf114,
+    icon_folder_open_alt     = 0xf115,
+
+    icon_expand_alt          = 0xf116,
+    icon_collapse_alt        = 0xf117,
+    icon_smile               = 0xf118,
+    icon_frown               = 0xf119,
+    icon_meh                 = 0xf11a,
+    icon_gamepad             = 0xf11b,
+    icon_keyboard            = 0xf11c,
+    icon_flag_alt            = 0xf11d,
+    icon_flag_checkered      = 0xf11e,
+
+    icon_terminal            = 0xf120,
+    icon_code                = 0xf121,
+    icon_reply_all           = 0xf122,
+    icon_mail_reply_all      = icon_reply_all,
+    icon_star_half_full      = 0xf123,
+    icon_star_half_empty     = icon_star_half_full,
+    icon_location_arrow      = 0xf124,
+    icon_crop                = 0xf125,
+    icon_code_fork           = 0xf126,
+    icon_unlink              = 0xf127,
+    icon_question            = 0xf128,
+    icon_info                = 0xf129,
+    icon_exclamation         = 0xf12a,
+    icon_superscript         = 0xf12b,
+    icon_subscript           = 0xf12c,
+    icon_eraser              = 0xf12d,
+    icon_puzzle_piece        = 0xf12e,
+
+    icon_microphone          = 0xf130,
+    icon_microphone_off      = 0xf131,
+    icon_shield              = 0xf132,
+    icon_calendar_empty      = 0xf133,
+    icon_fire_extinguisher   = 0xf134,
+    icon_rocket              = 0xf135,
+    icon_maxcdn              = 0xf136,
+    icon_chevron_sign_left   = 0xf137,
+    icon_chevron_sign_right  = 0xf138,
+    icon_chevron_sign_up     = 0xf139,
+    icon_chevron_sign_down   = 0xf13a,
+    icon_html5               = 0xf13b,
+    icon_css3                = 0xf13c,
+    icon_anchor              = 0xf13d,
+    icon_unlock_alt          = 0xf13e,
+
+    icon_bullseye            = 0xf140,
+    icon_ellipsis_horizontal = 0xf141,
+    icon_ellipsis_vertical   = 0xf142,
+    icon_rss_sign            = 0xf143,
+    icon_play_sign           = 0xf144,
+    icon_ticket              = 0xf145,
+    icon_minus_sign_alt      = 0xf146,
+    icon_check_minus         = 0xf147,
+    icon_level_up            = 0xf148,
+    icon_level_down          = 0xf149,
+    icon_check_sign          = 0xf14a,
+    icon_edit_sign           = 0xf14b,
+    icon_external_link_sign  = 0xf14c,
+    icon_share_sign          = 0xf14d,
+
+    // v3.2.0
+    icon_compass                = 0xf14e,
+
+    icon_collapse               = 0xf150,
+    icon_collapse_top           = 0xf151,
+    icon_expand                 = 0xf152,
+    icon_euro                   = 0xf153,
+    icon_eur                    = 0xf153,
+    icon_gbp                    = 0xf154,
+    icon_dollar                 = 0xf155,
+    icon_usd                    = icon_dollar,
+    icon_rupee                  = 0xf156,
+    icon_inr                    = icon_rupee,
+    icon_yen                    = 0xf157,
+    icon_jpy                    = icon_yen,
+    icon_renminbi               = 0xf158,
+    icon_cny                    = icon_renminbi,
+    icon_won                    = 0xf159,
+    icon_krw                    = icon_won,
+    icon_bitcoin                = 0xf15a,
+    icon_btc                    = icon_bitcoin,
+    icon_file                   = 0xf15b,
+    icon_file_text              = 0xf15c,
+    icon_sort_by_alphabet       = 0xf15d,
+    icon_sort_by_alphabet_alt   = 0xf15e,
+
+    icon_sort_by_attributes     = 0xf160,
+    icon_sort_by_attributes_alt = 0xf161,
+    icon_sort_by_order          = 0xf162,
+    icon_sort_by_order_alt      = 0xf163,
+    icon_thumbs_up              = 0xf164,
+    icon_thumbs_down            = 0xf165,
+    icon_youtube_sign           = 0xf166,
+    icon_youtube                = 0xf167,
+    icon_xing                   = 0xf168,
+    icon_xing_sign              = 0xf169,
+    icon_youtube_play           = 0xf16a,
+    icon_dropbox                = 0xf16b,
+    icon_stackexchange          = 0xf16c,
+    icon_instagram              = 0xf16d,
+    icon_flickr                 = 0xf16e,
+
+    icon_adn                    = 0xf170,
+    icon_bitbucket              = 0xf171,
+    icon_bitbucket_sign         = 0xf172,
+    icon_tumblr                 = 0xf173,
+    icon_tumblr_sign            = 0xf174,
+    icon_long_arrow_down        = 0xf175,
+    icon_long_arrow_up          = 0xf176,
+    icon_long_arrow_left        = 0xf177,
+    icon_long_arrow_right       = 0xf178,
+    icon_apple                  = 0xf179,
+    icon_windows                = 0xf17a,
+    icon_android                = 0xf17b,
+    icon_linux                  = 0xf17c,
+    icon_dribble                = 0xf17d,
+    icon_skype                  = 0xf17e,
+
+    icon_foursquare             = 0xf180,
+    icon_trello                 = 0xf181,
+    icon_female                 = 0xf182,
+    icon_male                   = 0xf183,
+    icon_gittip                 = 0xf184,
+    icon_sun                    = 0xf185,
+    icon_moon                   = 0xf186,
+    icon_archive                = 0xf187,
+    icon_bug                    = 0xf188,
+    icon_vk                     = 0xf189,
+    icon_weibo                  = 0xf18a,
+    icon_renren                 = 0xf18b,
+
+    icon_circle_close           = 0xf05c
+};
+
+
+//---------------------------------------------------------------------------------------
+
+class QtAwesomeIconPainter;
+
+/// The main class for managing icons
+/// This class requires a 2-phase construction. You must first create the class and then initialize it via an init* method
+class QtAwesome : public QObject
+{
+Q_OBJECT
+
+public:
+
+    QtAwesome(QObject *parent = 0);
+    virtual ~QtAwesome();
+
+    void init( const QString& fontname );
+    bool initFontAwesome();
+
+    void addNamedCodepoint( const QString& name, int codePoint );
+    QHash<QString,int> namedCodePoints() { return namedCodepoints_; }
+
+    void setDefaultOption( const QString& name, const QVariant& value  );
+    QVariant defaultOption( const QString& name );
+
+    QIcon icon( int character, const QVariantMap& options = QVariantMap() );
+    QIcon icon( const QString& name, const QVariantMap& options = QVariantMap() );
+    QIcon icon(QtAwesomeIconPainter* painter, const QVariantMap& optionMap = QVariantMap() );
+    QIcon icon(int character, const QColor& color);
+
+    void give( const QString& name, QtAwesomeIconPainter* painter );
+
+    QFont font( int size );
+
+    /// Returns the font-name that is used as icon-map
+    QString fontName() { return fontName_ ; }
+
+private:
+    QString fontName_;                                     ///< The font name used for this map
+    QHash<QString,int> namedCodepoints_;                   ///< A map with names mapped to code-points
+
+    QHash<QString, QtAwesomeIconPainter*> painterMap_;     ///< A map of custom painters
+    QVariantMap defaultOptions_;                           ///< The default icon options
+    QtAwesomeIconPainter* fontIconPainter_;                ///< A special painter fo painting codepoints
+};
+
+
+//---------------------------------------------------------------------------------------
+
+
+/// The QtAwesomeIconPainter is a specialized painter for painting icons
+/// your can implement an iconpainter to create custom font-icon code
+class QtAwesomeIconPainter
+{
+public:
+    virtual ~QtAwesomeIconPainter() {}
+    virtual void paint( QtAwesome* awesome, QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state, const QVariantMap& options ) = 0;
+};
+
+extern QtAwesome *awesome;
+
+#endif // QTAWESOME_H
diff --git a/third_party/QtAwesome/QtAwesome.qrc b/third_party/QtAwesome/QtAwesome.qrc
new file mode 100644 (file)
index 0000000..40ffd6a
--- /dev/null
@@ -0,0 +1,5 @@
+<RCC>
+       <qresource prefix="/">
+               <file>fonts/fontawesome.ttf</file>
+       </qresource>
+</RCC>
diff --git a/third_party/QtAwesome/fonts/fontawesome.ttf b/third_party/QtAwesome/fonts/fontawesome.ttf
new file mode 100755 (executable)
index 0000000..d365924
Binary files /dev/null and b/third_party/QtAwesome/fonts/fontawesome.ttf differ
diff --git a/ui/about-dialog.ui b/ui/about-dialog.ui
new file mode 100644 (file)
index 0000000..64c92b2
--- /dev/null
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AboutDialog</class>
+ <widget class="QDialog" name="AboutDialog">
+  <property name="enabled">
+   <bool>true</bool>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>296</width>
+    <height>137</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>About</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>false</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="sizeConstraint">
+    <enum>QLayout::SetMinimumSize</enum>
+   </property>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::MinimumExpanding</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>6</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeType">
+        <enum>QSizePolicy::MinimumExpanding</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>6</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QLabel" name="mVersionText">
+       <property name="font">
+        <font>
+         <family>Times New Roman</family>
+         <pointsize>18</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string notr="true">Current Version</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_3">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeType">
+        <enum>QSizePolicy::MinimumExpanding</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>6</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::MinimumExpanding</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>7</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mCheckUpdateBtn">
+       <property name="text">
+        <string>Check For Updates</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mOKBtn">
+       <property name="text">
+        <string>OK</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_4">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeType">
+        <enum>QSizePolicy::MinimumExpanding</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>6</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::MinimumExpanding</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>6</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="9"/>
+ <resources/>
+ <connections/>
+ <designerdata>
+  <property name="gridDeltaX">
+   <number>10</number>
+  </property>
+  <property name="gridDeltaY">
+   <number>10</number>
+  </property>
+  <property name="gridSnapX">
+   <bool>true</bool>
+  </property>
+  <property name="gridSnapY">
+   <bool>true</bool>
+  </property>
+  <property name="gridVisible">
+   <bool>false</bool>
+  </property>
+ </designerdata>
+</ui>
diff --git a/ui/account-settings-dialog.ui b/ui/account-settings-dialog.ui
new file mode 100644 (file)
index 0000000..589f267
--- /dev/null
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AccountSettingsDialog</class>
+ <widget class="QDialog" name="AccountSettingsDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>483</width>
+    <height>123</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QFormLayout" name="formLayout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Server Address</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLineEdit" name="mServerAddr"/>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>Email</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QLineEdit" name="mUsername"/>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mOkBtn">
+       <property name="text">
+        <string>OK</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mCancelBtn">
+       <property name="text">
+        <string>Cancel</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+  <zorder>mOkBtn</zorder>
+  <zorder>mServerAddr</zorder>
+  <zorder>mUsername</zorder>
+  <zorder>label</zorder>
+  <zorder>label_2</zorder>
+  <zorder></zorder>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>mCancelBtn</sender>
+   <signal>clicked()</signal>
+   <receiver>AccountSettingsDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>472</x>
+     <y>108</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>249</x>
+     <y>122</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/account-view.ui b/ui/account-view.ui
new file mode 100644 (file)
index 0000000..06cd209
--- /dev/null
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AccountView</class>
+ <widget class="QWidget" name="AccountView">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>398</width>
+    <height>66</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>15</number>
+   </property>
+   <property name="topMargin">
+    <number>12</number>
+   </property>
+   <property name="rightMargin">
+    <number>15</number>
+   </property>
+   <property name="bottomMargin">
+    <number>12</number>
+   </property>
+   <item>
+    <widget class="QToolButton" name="mAccountBtn">
+     <property name="text">
+      <string>Account</string>
+     </property>
+     <property name="autoRaise">
+      <bool>true</bool>
+     </property>
+     <property name="arrowType">
+      <enum>Qt::NoArrow</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout_5">
+     <property name="spacing">
+      <number>0</number>
+     </property>
+     <property name="leftMargin">
+      <number>10</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="mEmail">
+       <property name="text">
+        <string>email</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="mServerAddr">
+       <property name="font">
+        <font>
+         <pointsize>10</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>server</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="horizontalSpacer_4">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>248</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QLabel" name="mRefreshLabel">
+     <property name="text">
+      <string notr="true">RefreshIcon</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/clone-tasks-dialog.ui b/ui/clone-tasks-dialog.ui
new file mode 100644 (file)
index 0000000..f232839
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CloneTasksDialog</class>
+ <widget class="QDialog" name="CloneTasksDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>242</width>
+    <height>47</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QPushButton" name="mClearBtn">
+       <property name="text">
+        <string>Clear</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton">
+       <property name="text">
+        <string>Close</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pushButton</sender>
+   <signal>clicked()</signal>
+   <receiver>CloneTasksDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>71</x>
+     <y>50</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>22</x>
+     <y>45</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/cloud-view.ui b/ui/cloud-view.ui
new file mode 100644 (file)
index 0000000..8bea61b
--- /dev/null
@@ -0,0 +1,324 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CloudView</class>
+ <widget class="QWidget" name="CloudView">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>511</width>
+    <height>579</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true"/>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="mHeader" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_9">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="mLogo">
+        <property name="text">
+         <string>logo</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="mBrand">
+        <property name="text">
+         <string>brand</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_10">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <layout class="QVBoxLayout" name="verticalLayout_5">
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_10">
+          <item>
+           <widget class="QPushButton" name="mMinimizeBtn">
+            <property name="text">
+             <string>minimize</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="mCloseBtn">
+            <property name="text">
+             <string>close</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <spacer name="verticalSpacer_4">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="mDropArea" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_3">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <spacer name="verticalSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>40</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_6">
+        <item>
+         <widget class="QFrame" name="mDropInner">
+          <property name="frameShape">
+           <enum>QFrame::StyledPanel</enum>
+          </property>
+          <property name="frameShadow">
+           <enum>QFrame::Raised</enum>
+          </property>
+          <layout class="QHBoxLayout" name="horizontalLayout_7">
+           <property name="spacing">
+            <number>0</number>
+           </property>
+           <item>
+            <spacer name="horizontalSpacer_8">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item>
+            <widget class="QPushButton" name="mSelectFolderBtn">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="text">
+              <string>Select</string>
+             </property>
+             <property name="flat">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QLabel" name="mDropFolderText">
+             <property name="text">
+              <string>or Drop Folder to Sync</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <spacer name="horizontalSpacer_9">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <spacer name="verticalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>40</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QFrame" name="mFooter">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="leftMargin">
+       <number>10</number>
+      </property>
+      <property name="rightMargin">
+       <number>10</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QProgressBar" name="mStorageUsage">
+        <property name="value">
+         <number>0</number>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="mServerStatusBtn">
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="autoRaise">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_3">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <property name="leftMargin">
+         <number>20</number>
+        </property>
+        <item>
+         <widget class="QLabel" name="mDownloadRate">
+          <property name="text">
+           <string>download rate</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="mDownloadRateArrow">
+          <property name="text">
+           <string>downarrow</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_4">
+        <item>
+         <widget class="QLabel" name="mUploadRate">
+          <property name="text">
+           <string>upload rate</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="mUploadRateArrow">
+          <property name="text">
+           <string>uparrow</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/create-repo-dialog.ui b/ui/create-repo-dialog.ui
new file mode 100644 (file)
index 0000000..01fc313
--- /dev/null
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CreateRepoDialog</class>
+ <widget class="QDialog" name="CreateRepoDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>407</width>
+    <height>247</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QFrame" name="mFrame">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="lineWidth">
+      <number>0</number>
+     </property>
+     <layout class="QFormLayout" name="formLayout">
+      <property name="fieldGrowthPolicy">
+       <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+      </property>
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>Path:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <item>
+         <widget class="QLineEdit" name="mDirectory"/>
+        </item>
+        <item>
+         <widget class="QPushButton" name="mChooseDirBtn">
+          <property name="text">
+           <string>Choose</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="nameLabel">
+        <property name="text">
+         <string>Name:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLineEdit" name="mName">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QCheckBox" name="mEncrypteCheckBox">
+        <property name="text">
+         <string>encrypted</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0">
+       <widget class="QLabel" name="mPasswordLabel">
+        <property name="text">
+         <string>Password:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="1">
+       <widget class="QLineEdit" name="mPassword">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="autoFillBackground">
+         <bool>false</bool>
+        </property>
+        <property name="echoMode">
+         <enum>QLineEdit::Password</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="0">
+       <widget class="QLabel" name="mPasswordAgainLabel">
+        <property name="text">
+         <string>Password Again:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="1">
+       <widget class="QLineEdit" name="mPasswordAgain">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="echoMode">
+         <enum>QLineEdit::Password</enum>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="spacing">
+      <number>10</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="mStatusText">
+       <property name="enabled">
+        <bool>true</bool>
+       </property>
+       <property name="text">
+        <string>status text</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mOkBtn">
+       <property name="text">
+        <string>OK</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mCancelBtn">
+       <property name="text">
+        <string>Cancel</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>mOkBtn</tabstop>
+  <tabstop>mDirectory</tabstop>
+  <tabstop>mChooseDirBtn</tabstop>
+  <tabstop>mName</tabstop>
+  <tabstop>mEncrypteCheckBox</tabstop>
+  <tabstop>mPassword</tabstop>
+  <tabstop>mPasswordAgain</tabstop>
+  <tabstop>mCancelBtn</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>mCancelBtn</sender>
+   <signal>clicked()</signal>
+   <receiver>CreateRepoDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>396</x>
+     <y>439</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>339</x>
+     <y>4</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>mEncrypteCheckBox</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>mPassword</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>162</x>
+     <y>297</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>165</x>
+     <y>329</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>mEncrypteCheckBox</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>mPasswordAgain</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>200</x>
+     <y>296</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>239</x>
+     <y>358</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/download-repo-dialog.ui b/ui/download-repo-dialog.ui
new file mode 100644 (file)
index 0000000..8a79834
--- /dev/null
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DownloadRepoDialog</class>
+ <widget class="QDialog" name="DownloadRepoDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>551</width>
+    <height>366</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Download Library</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QFrame#mFrame {
+
+padding-top: 7px;
+
+}
+
+QLineEdit#mDirectory {
+
+min-width: 300px;
+
+}
+</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_4">
+   <item>
+    <widget class="QFrame" name="mFrame">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="lineWidth">
+      <number>0</number>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_3">
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <item>
+         <widget class="QLabel" name="mRepoIcon">
+          <property name="text">
+           <string notr="true">repoIcon</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="mRepoName">
+          <property name="text">
+           <string notr="true">repoName</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer_2">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QVBoxLayout" name="verticalLayout">
+        <item>
+         <widget class="QLabel" name="mOperationText">
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+          <property name="frameShadow">
+           <enum>QFrame::Plain</enum>
+          </property>
+          <property name="lineWidth">
+           <number>0</number>
+          </property>
+          <property name="text">
+           <string notr="true">Sync to folder:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_3">
+          <item>
+           <widget class="QLineEdit" name="mDirectory">
+            <property name="focusPolicy">
+             <enum>Qt::StrongFocus</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="mChooseDirBtn">
+            <property name="text">
+             <string>choose...</string>
+            </property>
+            <property name="default">
+             <bool>false</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QVBoxLayout" name="verticalLayout_2">
+        <property name="topMargin">
+         <number>5</number>
+        </property>
+        <item>
+         <widget class="QLabel" name="mPasswordLabel">
+          <property name="frameShadow">
+           <enum>QFrame::Plain</enum>
+          </property>
+          <property name="lineWidth">
+           <number>0</number>
+          </property>
+          <property name="text">
+           <string>Password for this library:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="mPassword">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="echoMode">
+           <enum>QLineEdit::Password</enum>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="mMergeHint">
+          <property name="font">
+           <font>
+            <strikeout>false</strikeout>
+           </font>
+          </property>
+          <property name="text">
+           <string notr="true"/>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <spacer name="verticalSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QFrame" name="mSwitchToSyncFrame">
+        <property name="frameShape">
+         <enum>QFrame::NoFrame</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Plain</enum>
+        </property>
+        <property name="lineWidth">
+         <number>0</number>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout_6">
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>5</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QLabel" name="mSwitchModeHint">
+           <property name="text">
+            <string notr="true">or merge with an existing folder </string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_4">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>235</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>18</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="spacing">
+      <number>10</number>
+     </property>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mOkBtn">
+       <property name="text">
+        <string>OK</string>
+       </property>
+       <property name="default">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mCancelBtn">
+       <property name="text">
+        <string>Cancel</string>
+       </property>
+       <property name="default">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>mChooseDirBtn</tabstop>
+  <tabstop>mPassword</tabstop>
+  <tabstop>mOkBtn</tabstop>
+  <tabstop>mCancelBtn</tabstop>
+  <tabstop>mDirectory</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>mCancelBtn</sender>
+   <signal>clicked()</signal>
+   <receiver>DownloadRepoDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>489</x>
+     <y>283</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>339</x>
+     <y>4</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/init-seafile-dialog.ui b/ui/init-seafile-dialog.ui
new file mode 100644 (file)
index 0000000..0406d00
--- /dev/null
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InitSeafileDialog</class>
+ <widget class="QDialog" name="InitSeafileDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>550</width>
+    <height>350</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <property name="styleSheet">
+      <string notr="true">background: white;</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_4">
+      <property name="bottomMargin">
+       <number>9</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="mTitle">
+        <property name="styleSheet">
+         <string notr="true"/>
+        </property>
+        <property name="text">
+         <string>Choose a folder</string>
+        </property>
+        <property name="margin">
+         <number>0</number>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_5">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>348</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="mLogo">
+        <property name="text">
+         <string>logo</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>125</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <property name="spacing">
+        <number>20</number>
+       </property>
+       <item>
+        <widget class="QLabel" name="mCentralText">
+         <property name="text">
+          <string>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</string>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <item>
+          <widget class="QLineEdit" name="mDirectory">
+           <property name="enabled">
+            <bool>true</bool>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>250</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="readOnly">
+            <bool>false</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="mChooseDirBtn">
+           <property name="text">
+            <string>Choose...</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_3">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>125</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="Line" name="line_2">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <property name="spacing">
+      <number>5</number>
+     </property>
+     <property name="leftMargin">
+      <number>10</number>
+     </property>
+     <property name="topMargin">
+      <number>10</number>
+     </property>
+     <property name="rightMargin">
+      <number>10</number>
+     </property>
+     <property name="bottomMargin">
+      <number>10</number>
+     </property>
+     <item>
+      <spacer name="horizontalSpacer_4">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mOkBtn">
+       <property name="text">
+        <string>Next</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mCancelBtn">
+       <property name="text">
+        <string>Cancel</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+  <zorder>line</zorder>
+  <zorder>line_2</zorder>
+  <zorder>widget</zorder>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/init-vdrive-dialog.ui b/ui/init-vdrive-dialog.ui
new file mode 100644 (file)
index 0000000..983bf7c
--- /dev/null
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InitVirtualDriveDialog</class>
+ <widget class="QDialog" name="InitVirtualDriveDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>566</width>
+    <height>350</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QLineEdit {
+min-width: 260px;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <property name="styleSheet">
+      <string notr="true">background: white;</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <item>
+       <widget class="QLabel" name="mTitle">
+        <property name="font">
+         <font>
+          <family>Sans Serif</family>
+          <pointsize>11</pointsize>
+         </font>
+        </property>
+        <property name="styleSheet">
+         <string notr="true"/>
+        </property>
+        <property name="text">
+         <string>Download Default Library</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_4">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>376</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="mLogo">
+        <property name="text">
+         <string>logo</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>85</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QWidget" name="mWrapper" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_3">
+      <item>
+       <widget class="QLabel" name="mStatusIcon">
+        <property name="text">
+         <string notr="true">TextLabel</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="mStatusText">
+        <property name="text">
+         <string>%1 organizes files by libraries. 
+Do you like to download your default library?</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_3">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>548</width>
+          <height>17</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>85</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="Line" name="line_2">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="spacing">
+      <number>10</number>
+     </property>
+     <property name="leftMargin">
+      <number>9</number>
+     </property>
+     <property name="topMargin">
+      <number>9</number>
+     </property>
+     <property name="rightMargin">
+      <number>9</number>
+     </property>
+     <property name="bottomMargin">
+      <number>9</number>
+     </property>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mYesBtn">
+       <property name="text">
+        <string>Yes</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mNoBtn">
+       <property name="text">
+        <string>Skip</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mRunInBackgroundBtn">
+       <property name="text">
+        <string>Run in Background</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mOpenBtn">
+       <property name="text">
+        <string>Open</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mFinishBtn">
+       <property name="text">
+        <string>Finish</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>mYesBtn</tabstop>
+  <tabstop>mNoBtn</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>mNoBtn</sender>
+   <signal>clicked()</signal>
+   <receiver>InitVirtualDriveDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>299</x>
+     <y>180</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>339</x>
+     <y>4</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/login-dialog.ui b/ui/login-dialog.ui
new file mode 100644 (file)
index 0000000..0716a31
--- /dev/null
@@ -0,0 +1,422 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LoginDialog</class>
+ <widget class="QDialog" name="LoginDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>550</width>
+    <height>349</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">QLineEdit {
+min-width: 260px;
+}</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <property name="styleSheet">
+      <string notr="true">background: white;</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <item>
+       <widget class="QLabel" name="mTitle">
+        <property name="font">
+         <font>
+          <family>Sans Serif</family>
+          <pointsize>11</pointsize>
+         </font>
+        </property>
+        <property name="styleSheet">
+         <string notr="true"/>
+        </property>
+        <property name="text">
+         <string>Add an account</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer_4">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>376</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="mLogo">
+        <property name="text">
+         <string>logo</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>85</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <layout class="QGridLayout" name="gridLayout">
+       <property name="topMargin">
+        <number>20</number>
+       </property>
+       <property name="bottomMargin">
+        <number>20</number>
+       </property>
+       <property name="spacing">
+        <number>10</number>
+       </property>
+       <item row="0" column="0">
+        <widget class="QLabel" name="serverUrl">
+         <property name="text">
+          <string>Server:</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1">
+        <widget class="QComboBox" name="mServerAddr">
+         <property name="editable">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <layout class="QVBoxLayout" name="serverNoteLayout">
+         <item>
+          <widget class="QLabel" name="hint">
+           <property name="lineWidth">
+            <number>1</number>
+           </property>
+           <property name="text">
+            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For example: https://seacloud.cc&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+           </property>
+           <property name="textFormat">
+            <enum>Qt::AutoText</enum>
+           </property>
+           <property name="openExternalLinks">
+            <bool>false</bool>
+           </property>
+           <property name="textInteractionFlags">
+            <set>Qt::LinksAccessibleByMouse</set>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="verticalSpacer2">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <height>-4</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QLabel" name="hint_2">
+           <property name="enabled">
+            <bool>true</bool>
+           </property>
+           <property name="text">
+            <string>or http://192.168.1.24:8000</string>
+           </property>
+           <property name="openExternalLinks">
+            <bool>false</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="verticalSpacer3">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <height>4</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+       <item row="2" column="0">
+        <widget class="QLabel" name="label_2">
+         <property name="text">
+          <string>Email / Username:</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1">
+        <widget class="QLineEdit" name="mUsername"/>
+       </item>
+       <item row="3" column="0">
+        <widget class="QLabel" name="label_3">
+         <property name="text">
+          <string>Password:</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="1">
+        <widget class="QLineEdit" name="mPassword">
+         <property name="echoMode">
+          <enum>QLineEdit::Password</enum>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="1">
+        <layout class="QVBoxLayout" name="automaticLoginLayout">
+         <item>
+          <spacer name="verticalSpacer4">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <height>-4</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="mAutomaticLogin">
+           <property name="text">
+            <string>Automatic Login</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="verticalSpacer5">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <height>4</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+       <item row="5" column="0">
+        <widget class="QLabel" name="label_5">
+         <property name="text">
+          <string>Computer Name:</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="1">
+        <widget class="QLineEdit" name="mComputerName"/>
+       </item>
+       <item row="6" column="1">
+        <widget class="QLabel" name="hint_3">
+         <property name="text">
+          <string>e.g. Jim's laptop</string>
+         </property>
+        </widget>
+       </item>
+       <item row="7" column="1">
+        <widget class="QLabel" name="mStatusText">
+         <property name="enabled">
+          <bool>true</bool>
+         </property>
+         <property name="text">
+          <string>status text</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_3">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>85</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="Line" name="line_2">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="spacing">
+      <number>10</number>
+     </property>
+     <property name="leftMargin">
+      <number>9</number>
+     </property>
+     <property name="topMargin">
+      <number>9</number>
+     </property>
+     <property name="rightMargin">
+      <number>9</number>
+     </property>
+     <property name="bottomMargin">
+      <number>9</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="mShibLoginLink">
+       <property name="text">
+        <string>Single Sign On</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mSubmitBtn">
+       <property name="text">
+        <string>Login</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mCancelBtn">
+       <property name="text">
+        <string>Cancel</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>mServerAddr</tabstop>
+  <tabstop>mUsername</tabstop>
+  <tabstop>mPassword</tabstop>
+  <tabstop>mComputerName</tabstop>
+  <tabstop>mSubmitBtn</tabstop>
+  <tabstop>mCancelBtn</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>mCancelBtn</sender>
+   <signal>clicked()</signal>
+   <receiver>LoginDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>299</x>
+     <y>180</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>339</x>
+     <y>4</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/private-share-dialog.ui b/ui/private-share-dialog.ui
new file mode 100644 (file)
index 0000000..c85b32d
--- /dev/null
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PrivateShareDialog</class>
+ <widget class="QDialog" name="PrivateShareDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>455</width>
+    <height>155</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QFrame" name="mFrame">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <item>
+       <layout class="QGridLayout" name="gridLayout">
+        <item row="0" column="0">
+         <widget class="QLabel" name="label">
+          <property name="text">
+           <string>Share To:</string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="2">
+         <widget class="QPushButton" name="mOkBtn">
+          <property name="text">
+           <string>Share</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_2">
+          <property name="text">
+           <string>Permission:</string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QComboBox" name="mPermission">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <item>
+           <property name="text">
+            <string>Read-Write</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Read-Only</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QStackedWidget" name="mInputStack">
+          <property name="currentIndex">
+           <number>0</number>
+          </property>
+          <widget class="QWidget" name="page"/>
+          <widget class="QWidget" name="page_2"/>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <property name="spacing">
+      <number>10</number>
+     </property>
+     <property name="leftMargin">
+      <number>8</number>
+     </property>
+     <property name="rightMargin">
+      <number>8</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="mStatusText">
+       <property name="enabled">
+        <bool>true</bool>
+       </property>
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mCancelBtn">
+       <property name="text">
+        <string>Close</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/repo-detail-dialog.ui b/ui/repo-detail-dialog.ui
new file mode 100644 (file)
index 0000000..389b690
--- /dev/null
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RepoDetailDialog</class>
+ <widget class="QDialog" name="RepoDetailDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>261</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="leftMargin">
+    <number>9</number>
+   </property>
+   <property name="rightMargin">
+    <number>9</number>
+   </property>
+   <item>
+    <widget class="QFrame" name="mFrame">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>12</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="mRepoIcon">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>RepoIcon</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <layout class="QFormLayout" name="formLayout">
+        <property name="fieldGrowthPolicy">
+         <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+        </property>
+        <property name="verticalSpacing">
+         <number>3</number>
+        </property>
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_5">
+          <property name="text">
+           <string>Name:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QLabel" name="mRepoName">
+          <property name="text">
+           <string>RepoName</string>
+          </property>
+          <property name="wordWrap">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_6">
+          <property name="text">
+           <string>Owner:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QLabel" name="mOwnerLabel">
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <spacer name="verticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>10</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="3" column="0">
+         <widget class="QLabel" name="label_3">
+          <property name="text">
+           <string>Last Modified:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="1">
+         <widget class="QLabel" name="mTimeLabel">
+          <property name="text">
+           <string>mtime</string>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="0">
+         <widget class="QLabel" name="label">
+          <property name="text">
+           <string>Size:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="1">
+         <widget class="QLabel" name="mSizeLabel">
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+         </widget>
+        </item>
+        <item row="6" column="0">
+         <spacer name="verticalSpacer_2">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>10</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="7" column="0">
+         <widget class="QLabel" name="lpathLabel">
+          <property name="text">
+           <string>Local Path:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="7" column="1">
+         <widget class="QLabel" name="mLpathLabel">
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+          <property name="textInteractionFlags">
+           <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+          </property>
+         </widget>
+        </item>
+        <item row="8" column="0">
+         <widget class="QLabel" name="label_4">
+          <property name="text">
+           <string>Status:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="8" column="1">
+         <widget class="QLabel" name="mStatus">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="layoutDirection">
+           <enum>Qt::LeftToRight</enum>
+          </property>
+          <property name="text">
+           <string>RepoStatus</string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+          </property>
+          <property name="wordWrap">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="9" column="0">
+         <widget class="QLabel" name="mSyncIntervalLabel">
+          <property name="text">
+           <string>Sync Interval:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="9" column="1">
+         <widget class="QLabel" name="mSyncInterval">
+          <property name="text">
+           <string/>
+          </property>
+         </widget>
+        </item>
+        <item row="10" column="0">
+         <spacer name="verticalSpacer_3">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>10</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton">
+       <property name="text">
+        <string>Close</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pushButton</sender>
+   <signal>clicked()</signal>
+   <receiver>RepoDetailDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>282</x>
+     <y>208</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>188</x>
+     <y>210</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/server-repo-item.ui b/ui/server-repo-item.ui
new file mode 100644 (file)
index 0000000..5d7672c
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerRepoItem</class>
+ <widget class="QWidget" name="ServerRepoItem">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>247</width>
+    <height>45</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <item>
+    <widget class="QLabel" name="mRepoIcon">
+     <property name="text">
+      <string>repoicon</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="mRepoName">
+     <property name="text">
+      <string>reponame</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="mDownloadButton">
+     <property name="text">
+      <string>download</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/server-repos-view.ui b/ui/server-repos-view.ui
new file mode 100644 (file)
index 0000000..db3c8e7
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerReposView</class>
+ <widget class="QWidget" name="ServerReposView">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QScrollArea" name="mScrollArea">
+     <property name="widgetResizable">
+      <bool>true</bool>
+     </property>
+     <widget class="QWidget" name="scrollAreaWidgetContents">
+      <property name="geometry">
+       <rect>
+        <x>0</x>
+        <y>0</y>
+        <width>380</width>
+        <height>245</height>
+       </rect>
+      </property>
+     </widget>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QPushButton" name="mRefreshButton">
+       <property name="text">
+        <string>Refresh</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mAddRepoButton">
+       <property name="text">
+        <string>Add a repo</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/server-status-dialog.ui b/ui/server-status-dialog.ui
new file mode 100644 (file)
index 0000000..30e5127
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerStatusDialog</class>
+ <widget class="QDialog" name="ServerStatusDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>274</width>
+    <height>245</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QListWidget" name="mList"/>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton">
+       <property name="text">
+        <string>Close</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pushButton</sender>
+   <signal>clicked()</signal>
+   <receiver>ServerStatusDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>299</x>
+     <y>268</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>247</x>
+     <y>276</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/set-repo-password-dialog.ui b/ui/set-repo-password-dialog.ui
new file mode 100644 (file)
index 0000000..dcf4bdf
--- /dev/null
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SetRepoPasswordDialog</class>
+ <widget class="QDialog" name="SetRepoPasswordDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>432</width>
+    <height>139</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <widget class="QFrame" name="frame">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <item>
+       <spacer name="verticalSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>90</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="mHintText">
+        <property name="text">
+         <string notr="true">Provide password for the library</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="mPassword">
+        <property name="inputMethodHints">
+         <set>Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText</set>
+        </property>
+        <property name="echoMode">
+         <enum>QLineEdit::Password</enum>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="mErrorText">
+        <property name="text">
+         <string notr="true">error message</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="verticalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>0</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mOkBtn">
+       <property name="text">
+        <string>OK</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mCancelBtn">
+       <property name="text">
+        <string>Cancel</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>mCancelBtn</sender>
+   <signal>clicked()</signal>
+   <receiver>SetRepoPasswordDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>389</x>
+     <y>112</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>184</x>
+     <y>114</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/settings-dialog.ui b/ui/settings-dialog.ui
new file mode 100644 (file)
index 0000000..ec4255d
--- /dev/null
@@ -0,0 +1,576 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>724</width>
+    <height>579</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_3">
+   <item>
+    <widget class="QTabWidget" name="mTabWidget">
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="mBasicTab">
+      <attribute name="title">
+       <string>Basic</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <item>
+        <widget class="QCheckBox" name="mHideMainWinCheckBox">
+         <property name="text">
+          <string>Hide main window when started</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="mNotifyCheckBox">
+         <property name="text">
+          <string>Notify when libraries are synchronized</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="mSyncExtraTempFileCheckBox">
+         <property name="text">
+          <string>Enable sync temporary files of MSOffice/Libreoffice</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="mAutoStartCheckBox">
+         <property name="text">
+          <string>Auto start %1 after login</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="mHideDockIconCheckBox">
+         <property name="text">
+          <string>Hide %1 Icon from the dock</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="mFinderSyncCheckBox">
+         <property name="text">
+          <string>Enable FinderSync Extension</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="mShellExtCheckBox">
+         <property name="text">
+          <string>Enable Explorer Extension</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="mCheckLatestVersionBox">
+         <property name="text">
+          <string>Check for updates automatically</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QFormLayout" name="formLayout">
+         <property name="labelAlignment">
+          <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+         </property>
+         <property name="formAlignment">
+          <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+         </property>
+         <item row="0" column="0">
+          <widget class="QLabel" name="label_5">
+           <property name="text">
+            <string>Download speed limit (KB/s):</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QLabel" name="label_4">
+           <property name="text">
+            <string>Upload speed limit (KB/s):</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QSpinBox" name="mDownloadSpinBox">
+           <property name="maximumSize">
+            <size>
+             <width>100</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="maximum">
+            <number>100000</number>
+           </property>
+           <property name="singleStep">
+            <number>10</number>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QSpinBox" name="mUploadSpinBox">
+           <property name="maximumSize">
+            <size>
+             <width>100</width>
+             <height>16777215</height>
+            </size>
+           </property>
+           <property name="maximum">
+            <number>100000</number>
+           </property>
+           <property name="singleStep">
+            <number>10</number>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="mAdvancedTab">
+      <attribute name="title">
+       <string>Advanced</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_2">
+       <item>
+        <widget class="QCheckBox" name="mAllowInvalidWorktreeCheckBox">
+         <property name="text">
+          <string>Do not automatically unsync a library</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLabel" name="desc">
+         <property name="text">
+          <string>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</string>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="mAllowRepoNotFoundCheckBox">
+         <property name="text">
+          <string>Do not unsync a library when not found on server</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLabel" name="desc_2">
+         <property name="text">
+          <string>Do not automatically unsync a library when it's not found on server</string>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="mDisableVerifyHttpSyncCert">
+         <property name="text">
+          <string>Do not verify server certificate in HTTPS syncing</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QCheckBox" name="mEnableSyncingWithExistingFolder">
+         <property name="text">
+          <string>Enable syncing with an existing folder with a different name</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="mLanguageTab">
+      <attribute name="title">
+       <string>Language</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="languageTabLayout">
+       <item>
+        <layout class="QHBoxLayout" name="languageLayout">
+         <item>
+          <widget class="QLabel" name="mLanguageLabel">
+           <property name="text">
+            <string>Language (need restart)</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QComboBox" name="mLanguageComboBox"/>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <spacer name="verticalSpacer_1">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="mNetworkTab">
+      <attribute name="title">
+       <string>Network</string>
+      </attribute>
+      <widget class="QWidget" name="layoutWidget">
+       <property name="geometry">
+        <rect>
+         <x>21</x>
+         <y>12</y>
+         <width>481</width>
+         <height>451</height>
+        </rect>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout_4">
+        <property name="spacing">
+         <number>6</number>
+        </property>
+        <item>
+         <layout class="QFormLayout" name="formLayout_2">
+          <property name="labelAlignment">
+           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+          </property>
+          <property name="formAlignment">
+           <set>Qt::AlignHCenter|Qt::AlignTop</set>
+          </property>
+          <property name="horizontalSpacing">
+           <number>10</number>
+          </property>
+          <property name="verticalSpacing">
+           <number>6</number>
+          </property>
+          <property name="topMargin">
+           <number>5</number>
+          </property>
+          <property name="rightMargin">
+           <number>4</number>
+          </property>
+          <item row="0" column="0">
+           <widget class="QLabel" name="mProxyMethodLabel">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>0</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="text">
+             <string>Proxy Type:</string>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="0" colspan="2">
+           <widget class="QComboBox" name="mProxyMethodComboBox">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>246</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="currentIndex">
+             <number>-1</number>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QLabel" name="mProxyHostLabel">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string>Host:</string>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QLineEdit" name="mProxyHost">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>240</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="0">
+           <widget class="QLabel" name="mProxyPortLabel">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string>Port:</string>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="1">
+           <widget class="QSpinBox" name="mProxyPort">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>256</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+            </property>
+            <property name="text" stdset="0">
+             <string>0</string>
+            </property>
+            <property name="maximum">
+             <number>65535</number>
+            </property>
+           </widget>
+          </item>
+          <item row="4" column="0">
+           <widget class="QLabel" name="mProxyUsernameLabel">
+            <property name="enabled">
+             <bool>false</bool>
+            </property>
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string>Username:</string>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+            </property>
+           </widget>
+          </item>
+          <item row="4" column="1">
+           <widget class="QLineEdit" name="mProxyUsername">
+            <property name="enabled">
+             <bool>false</bool>
+            </property>
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>240</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+            </property>
+           </widget>
+          </item>
+          <item row="5" column="0">
+           <widget class="QLabel" name="mProxyPasswordLabel">
+            <property name="enabled">
+             <bool>false</bool>
+            </property>
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string>Password:</string>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+            </property>
+           </widget>
+          </item>
+          <item row="5" column="1">
+           <widget class="QLineEdit" name="mProxyPassword">
+            <property name="enabled">
+             <bool>false</bool>
+            </property>
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>240</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="echoMode">
+             <enum>QLineEdit::Password</enum>
+            </property>
+            <property name="alignment">
+             <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+            </property>
+           </widget>
+          </item>
+          <item row="3" column="1">
+           <widget class="QCheckBox" name="mProxyRequirePassword">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>240</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="text">
+             <string>Proxy server requires a password</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <spacer name="verticalSpacer_2">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
+     </widget>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="spacing">
+      <number>10</number>
+     </property>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mOkBtn">
+       <property name="text">
+        <string>OK</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mCancelBtn">
+       <property name="text">
+        <string>Cancel</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>mCancelBtn</sender>
+   <signal>clicked()</signal>
+   <receiver>SettingsDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>711</x>
+     <y>566</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>249</x>
+     <y>249</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/ssl-confirm-dialog.ui b/ui/ssl-confirm-dialog.ui
new file mode 100644 (file)
index 0000000..bb454d3
--- /dev/null
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SslConfirmDialog</class>
+ <widget class="QDialog" name="SslConfirmDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>166</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="mHint">
+     <property name="text">
+      <string notr="true">hint</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QCheckBox" name="mRememberChoiceCheckBox">
+     <property name="text">
+      <string>Remember my choice</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="topMargin">
+      <number>0</number>
+     </property>
+     <property name="bottomMargin">
+      <number>0</number>
+     </property>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mYesBtn">
+       <property name="text">
+        <string>Yes</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mNoBtn">
+       <property name="text">
+        <string>No</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>mYesBtn</tabstop>
+  <tabstop>mRememberChoiceCheckBox</tabstop>
+  <tabstop>mNoBtn</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/two-factor-dialog.ui b/ui/two-factor-dialog.ui
new file mode 100644 (file)
index 0000000..1c0b4c6
--- /dev/null
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TwoFactorDialog</class>
+ <widget class="QDialog" name="TwoFactorDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>303</width>
+    <height>134</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>0</width>
+    <height>0</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="mText">
+     <property name="text">
+      <string>mText</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLineEdit" name="mLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>21</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>16777215</width>
+       <height>20</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QCheckBox" name="mRememberDevice">
+     <property name="text">
+      <string>Remember this device</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton_2">
+       <property name="text">
+        <string>Cancel</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mSubmit">
+       <property name="text">
+        <string>OK</string>
+       </property>
+       <property name="default">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pushButton_2</sender>
+   <signal>clicked()</signal>
+   <receiver>TwoFactorDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>167</x>
+     <y>105</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>151</x>
+     <y>66</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/ui/uninstall-helper-dialog.ui b/ui/uninstall-helper-dialog.ui
new file mode 100644 (file)
index 0000000..b95abff
--- /dev/null
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UninstallHelperDialog</class>
+ <widget class="QDialog" name="UninstallHelperDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>595</width>
+    <height>453</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>176</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_6">
+     <item>
+      <widget class="QLabel" name="mText">
+       <property name="text">
+        <string>text</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_6">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>175</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_5">
+     <item>
+      <spacer name="horizontalSpacer_5">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mYesBtn">
+       <property name="text">
+        <string>Yes</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="mNoBtn">
+       <property name="text">
+        <string>No</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+  <zorder>line</zorder>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/welcome-dialog.ui b/ui/welcome-dialog.ui
new file mode 100644 (file)
index 0000000..8e18b78
--- /dev/null
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>WelcomeDialog</class>
+ <widget class="QDialog" name="WelcomeDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>566</width>
+    <height>543</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="font">
+      <font>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">background: white;</string>
+     </property>
+     <property name="text">
+      <string>Welcome to the seafile client</string>
+     </property>
+     <property name="margin">
+      <number>15</number>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="mHelpImage">
+     <property name="text">
+      <string>HelpImage</string>
+     </property>
+     <property name="margin">
+      <number>20</number>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_2">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;To sync files with a Seafile server:&lt;br/&gt;&lt;/p&gt;&lt;p&gt;1. Add an account (with server address and your email)&lt;/p&gt;&lt;p&gt;2. Download a library&lt;/p&gt;&lt;p&gt;3. Put files into the library and they will be uploaded to server automatically&lt;br/&gt;&lt;/p&gt;&lt;p&gt;You can also create a library from any local folder. See &lt;a href=&quot;http://www.seafile.com/en/help/install_v2/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;seafile online help&lt;/span&gt;&lt;/a&gt; for more information.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+     <property name="margin">
+      <number>20</number>
+     </property>
+     <property name="openExternalLinks">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>101</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="rightMargin">
+      <number>9</number>
+     </property>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton">
+       <property name="text">
+        <string>Next</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pushButton</sender>
+   <signal>clicked()</signal>
+   <receiver>WelcomeDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>347</x>
+     <y>231</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>388</x>
+     <y>258</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>